Objective of workshop
To create scatter and bar plot visualisations using the ggplot2
package.
What this workshop will cover
In this workshop, the aim is to cover how to use the ggplot2 package.
We will be covering:
- An introduction to the ggplot2 package
- How to make scatter plots with ggplot2
- How to make bar plots with ggplot2
- How to change colours and other features in your visualisations
Introduction
Data visualisation is a way of looking at your data using graphics,
which provides a different perspective to your data.
There are a lot of different options for data visualistion with R.
You can use the visualisation tools that come with R, ggplot and all its
extensions, or for interactive visualisations there is the plotly
library.

In this data visualisation series we will be mainly focussing on
ggplot, as well as plotly. While the visualistion tools that come with R
are useful, ggplot and plotly are generally easier to use and make great
visualisations with. For this tutorial we will be using the below
packages: ggplot2, dplyr, readr, janitor. Run the code below to install
the packages if you don’t have them installed already.
# install packages
install <- c("ggplot2", "dplyr", "readr",
"janitor", "RColorBrewer",
"forcats")
install.packages(install, Ncpus = 6)
Then we need to load them into our session. Run the code chunk below
to load all the libraries you will need.
# load packages
library(ggplot2)
library(dplyr)
library(readr)
library(janitor)
library(RColorBrewer)
library(forcats)
What is ggplot and how does it work?
ggplot2 is a package for producing graphics that works by combining
independent components when making graphs, known as layers. This makes
ggplot2 both versatile and powerful; you are not limited by a set of
options but instead can make novel graphics to suit your needs.
It is also important to note that ggplot can only use data frames. If
your data is in another format you will need to transform it into a data
frame in order to use ggplot.
In order to understand how the layers work we will first load in some
data for our examples. We will use data from the Pokémon games, which
was web scraped from https://pokemondb.net/pokedex/all.
# load and clean names
pokemon <- read_csv("https://raw.githubusercontent.com/andrewmoles2/webScraping/main/R/data/pokemon.csv") %>%
clean_names()
# review data
pokemon %>%
glimpse()
## Rows: 966
## Columns: 14
## $ number <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, …
## $ name <chr> "Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmele…
## $ type1 <chr> "Grass", "Grass", "Grass", "Fire", "Fire", "Fire", "Water",…
## $ type2 <chr> "Poison", "Poison", "Poison", NA, NA, "Flying", NA, NA, NA,…
## $ total <dbl> 318, 405, 525, 309, 405, 534, 314, 405, 530, 195, 205, 395,…
## $ hp <dbl> 45, 60, 80, 39, 58, 78, 44, 59, 79, 45, 50, 60, 40, 45, 65,…
## $ attack <dbl> 49, 62, 82, 52, 64, 84, 48, 63, 83, 30, 20, 45, 35, 25, 90,…
## $ defense <dbl> 49, 63, 83, 43, 58, 78, 65, 80, 100, 35, 55, 50, 30, 50, 40…
## $ sp_atk <dbl> 65, 80, 100, 60, 80, 109, 50, 65, 85, 20, 25, 90, 20, 25, 4…
## $ sp_def <dbl> 65, 80, 100, 50, 65, 85, 64, 80, 105, 20, 25, 80, 20, 25, 8…
## $ speed <dbl> 45, 60, 80, 65, 80, 100, 43, 58, 78, 45, 30, 70, 50, 35, 75…
## $ legendary <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FAL…
## $ generation <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ image_url <chr> "https://img.pokemondb.net/sprites/home/normal/bulbasaur.pn…
The syntax for ggplot has three key components. The ggplot function
call (ggplot()), the aesthetics (called
aes()), and the geometry (called geoms) which refers to
scatter, bar, or line plots for example. The next three code chunks
break this down.
# call ggplot2 and add data
ggplot(pokemon)

Notice we just get a grey box. We have just loaded our data into
ggplot but not much else! Now lets add the aesthetics and see what
happens.
Too add aesthetics we use the aes() function within the
ggplot() function, and specify what our x and y axis will
be with column names from our data, sp_atk and sp_def in this case.
# add aesthetics
ggplot(pokemon, aes(x = sp_atk, y = sp_def))

It is starting to look more like a visualisation now, we can see the
x and y axis labels, but we still have no data points showing. We have
to add a geometry for that to happen. Notice the syntax here, we use the
+ icon to add a geometry to ggplot, which in this case is
geom_point() which makes scatter plots. All geometry
functions start with geom_ and end with the type of
geometry such as point, bar, or line.
# pick which geometry
ggplot(pokemon, aes(x = sp_atk, y = sp_def)) +
geom_point()

This is the fundamental concept of ggplot, you construct your
visualisations in layers, adding geometry layers, and other features as
you go.
what is ggplot exercise
Using the pokemon data, make a scatter plot with hp on the x
axis and speed on the y axis.
Scatter plots
Scatter plots are for displaying the relationship between two numeric
(or quantitative) variables. For each data point, the values of its
first variable is represented on the X axis and the second on the Y
axis.
To make a scatter plot with ggplot2 we use the
geom_point() function like you just saw. In order for
ggplot to make a scatter plot, the X and Y axis must be numeric.
The plot we just made in the example is okay but it could do with
some improving. There are quite a few different ways to change the
appearance of a visualisation, lets go through them.
The first thing we will look at is adding some colour! There are a
few options for adding colours to your plots. You can add the name, such
as red, or you can use a hex code, or you can use a pre-defined palette.
To add colour to a scatter plot we use the colour =
argument.
# colour of points
ggplot(pokemon, aes(x = hp, y = speed)) +
geom_point(colour = "orange")

To colour your points by a group (or factor) we have to add the
colour argument into the aes() function. This allows us to
have different colours for different groups, which makes the plot more
informative.
In the below example, our data is coloured by if a pokemon is
classified as legendary or not.
# colour by factor
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary)) +
geom_point()

We get the default ggplot colours which are okay. There are a few
different ways of changing the colours, all methods use the
scale_ function in a slightly different way. In the two
examples below we have changed the colours using the RColorBrewer
package and have set the colours manually.
RColorBrewer comes with a set of palettes for different situations,
you can view them by following this link https://www.r-graph-gallery.com/38-rcolorbrewers-palettes.html.
To use these palettes with ggplot we use the
scale_colour_brewer() function with an argument for which
palette we want to use; in this example we are using Set1.
library(RColorBrewer)
# adjusting colour by factor using RColorBrewer
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary)) +
geom_point() +
scale_colour_brewer(palette = "Set1")

To make a manual palette, you first make a vector with your colours,
to do so it is useful to use a colour picker such as http://tristen.ca/hcl-picker/#/hlc/6/1/15534C/E2E062 or
https://coolors.co/. You
copy the hex code (code with # then 6 numbers of letters) and paste it
into your vector like you can see in the manual_pal vector below. To add
the colour we use scale_colour_manual() function, and set
the values to our manual palette.
# adjusting colour by factor using manual palette
manual_pal <- c("#90C0F8", "#EA964E")
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary)) +
geom_point() +
scale_colour_manual(values = manual_pal)

It is sometimes helpful to view the palette before using it. We can
use the scales package for this, which is installed when you install
ggplot2. We provide the show_col() function with the
palette we want to view and it returns a grid view of the colours. In
the example we look at Set1 from RColorBrewer and the manual palette we
just used.
# load scales
library(scales)
##
## Attaching package: 'scales'
## The following object is masked from 'package:readr':
##
## col_factor
# view palettes
show_col(RColorBrewer::brewer.pal(n = 8, name = "Set1"))


As well as changing the colour of the points, you can change their
shape, size, and transparency (alpha). Just like with colour, we can
define the size, shape or transparency either in the aes()
function or in a geom_ function. By adding them to the
geom_ function we manually change them. If we use them in
aes() we have to associate the size/shape/alpha with a
variable.
See the below example, first we manually set the size and alpha. In
the second example we set the size to be defined by the total column in
our pokemon data, and manually set the alpha.
# manually set size and alpha
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary)) +
geom_point(size = 5, alpha = 0.6) +
scale_colour_brewer(palette = "Set1")

# manually set alpha, size by total
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary, size = total)) +
geom_point(alpha = 0.6) +
scale_colour_brewer(palette = "Set1")

To manually change the shape and replace the circles, we give the
shape argument a number. Each number represents a shape, letter, or
number; by default ggplot uses shape number 19. We can change the shape
to a square for example by using the number 15.
# default shape number
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary, size = total)) +
geom_point(alpha = 0.6, shape = 19) +
scale_colour_brewer(palette = "Set1")

# shape number for squares
ggplot(pokemon, aes(x = hp, y = speed, colour = legendary, size = total)) +
geom_point(alpha = 0.6, shape = 15) +
scale_colour_brewer(palette = "Set1")

View the image with the visual markdown editor to see what number
represents what shape, letter, or number.

Finally we can add a title and save our plot! We’ve done two things
in order to achieve this. To add a title, and change axis labels, we
have used the labs() function. We add arguments for what we
want to change, such as
title = "Pokemon Hit Points vs Speed". To change the legend
labels we use colour and size, as we used these to define our legend in
the aes() function.
To save the plot we assign our code to a variable, then we use the
ggsave() function, which requires what you want to call the
file and the file extension (e.g. plot.PNG or plot.JPG), then the ggplot
object we created. Run the example below, and you should get a
hp_vs_speed.PNG file where your Rmd file is saved. You can also adjust
the size of the image saved using the width and height arguments.
# save plot to a variable
hp_vs_speed <- ggplot(pokemon, aes(x = hp, y = speed, colour = legendary, size = total)) +
geom_point(alpha = 0.6, shape = 15) +
scale_colour_brewer(palette = "Set1") +
labs(title = "Pokemon Hit Points vs Speed",
subtitle = "Taken from pokemondb.net",
x = "Hit Points",
y = "Speed",
colour = "Legenary pokemon?",
size = "Total stats")
hp_vs_speed

# save plot
ggsave("hp_vs_speed.PNG", hp_vs_speed)
## Saving 7 x 5 in image
# save with defined width and height
ggsave("hp_vs_speed.PNG", hp_vs_speed,
width = 7, height = 4.5)
Scatter plots exercise
For the exercises in this workshop we will use data from the Olympics
that includes all Olympic games from 1896 through to 2016. More
information on the dataset can be found here https://github.com/rfordatascience/tidytuesday/blob/master/data/2021/2021-07-27/readme.md.
Run the code provided to load the libraries and data into R.
We will make two scatter plots from the Olympics data. For both plots
we will use dplyr to filter the information we are interested in, which
has been done for you in this exercise.
- Using the provided
scatter_plot1 data, make a scatter
plot of Olympic gymnasts heights (x axis) and weights (y axis).
- Change the colour and shape arguments to tell us what sex the
gymnasts are.
- Change the colour palette by making a manual one or using
RColorBrewer.
- Be sure to give your plot a title, and save your plot.
- Using the provided
scatter_plot2 data, make a scatter
plot of the age (y axis) of gymnastic medal winners by year (x
axis).
- Colour your plot by medal by making a manual colour palette.
hint: the hex codes for gold, silver and bronze are: “#FFD700”,
“#C0C0C0”, “#CD7F32”
- Use shape to tell us what sex the gymnasts were.
- Be sure to give your plot a title, and save your plot.
# make sure libraries are loaded
library(readr)
library(dplyr)
library(ggplot2)
library(RColorBrewer)
# load in data
olympics <- read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-07-27/olympics.csv")
## Rows: 271116 Columns: 15
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (10): name, sex, team, noc, games, season, city, sport, event, medal
## dbl (5): id, age, height, weight, year
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 271,116
## Columns: 15
## $ id <dbl> 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, …
## $ name <chr> "A Dijiang", "A Lamusi", "Gunnar Nielsen Aaby", "Edgar Lindenau…
## $ sex <chr> "M", "M", "M", "M", "F", "F", "F", "F", "F", "F", "M", "M", "M"…
## $ age <dbl> 24, 23, 24, 34, 21, 21, 25, 25, 27, 27, 31, 31, 31, 31, 33, 33,…
## $ height <dbl> 180, 170, NA, NA, 185, 185, 185, 185, 185, 185, 188, 188, 188, …
## $ weight <dbl> 80, 60, NA, NA, 82, 82, 82, 82, 82, 82, 75, 75, 75, 75, 75, 75,…
## $ team <chr> "China", "China", "Denmark", "Denmark/Sweden", "Netherlands", "…
## $ noc <chr> "CHN", "CHN", "DEN", "DEN", "NED", "NED", "NED", "NED", "NED", …
## $ games <chr> "1992 Summer", "2012 Summer", "1920 Summer", "1900 Summer", "19…
## $ year <dbl> 1992, 2012, 1920, 1900, 1988, 1988, 1992, 1992, 1994, 1994, 199…
## $ season <chr> "Summer", "Summer", "Summer", "Summer", "Winter", "Winter", "Wi…
## $ city <chr> "Barcelona", "London", "Antwerpen", "Paris", "Calgary", "Calgar…
## $ sport <chr> "Basketball", "Judo", "Football", "Tug-Of-War", "Speed Skating"…
## $ event <chr> "Basketball Men's Basketball", "Judo Men's Extra-Lightweight", …
## $ medal <chr> NA, NA, NA, "Gold", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
# data cleaning for first scatter plot
scatter_plot1 <- olympics %>%
filter(sport == "Gymnastics")
# data cleaning for second scatter plot
scatter_plot2 <- olympics %>%
filter(sport == "Gymnastics") %>%
filter(!is.na(medal)) %>%
mutate(medal = factor(medal, levels = c("Gold", "Silver", "Bronze")))
# your code here
Quirks of ggplot2
There are a few quirks to be aware of when using ggplot2 and you’ll
see a few of them when you look for examples online. In order to aid
with this, we can have a look at a few of them!
The first quirk is piping data into ggplot, where you do not need to
add your data into the ggplot() function as it is piped in.
The main advantage of this approach is you can string together some data
cleaning and then pipe the results straight into ggplot.
# piping data into ggplot
pokemon %>%
ggplot(aes(x = sp_atk, y = sp_def)) +
geom_point()

# piping with filter
pokemon %>%
filter(type1 == "Fire") %>%
ggplot(aes(x = sp_atk, y = sp_def)) +
geom_point()

The second quirk is adding aesthetics into a geom_
function rather than the ggplot() function.
# adding aesthetics into the geom_ call
ggplot(pokemon) +
geom_point(aes(x = sp_atk, y = sp_def))

The third quirk is you can also add the data into the
geom_ function. When doing so you have to have
data = otherwise you will get an error.
# adding data and aesthetics into the geom_ call
ggplot() +
geom_point(data = pokemon, aes(x = sp_atk, y = sp_def))

The fourth quirk relates to the second and third, in that you can add
aesthetics into a geom_ function more than once. You might
occasionally come across this for more complex visualisations.
In the example we will add the average of our x and y variables.
First we make a summary table that has the averages of both axis’s,
using summarise() from dplyr. Then we add two
geom_point() functions, one with the pokemon data, and one
with our summary table data.
# why adding aesthetics into the geom_ call
# calculate mean of sp_atk and sp_def
avg_sp <- pokemon %>%
summarise(
avg_sp_atk = mean(sp_atk, na.rm = TRUE),
avg_sp_def = mean(sp_def, na.rm = TRUE))
avg_sp
## # A tibble: 1 × 2
## avg_sp_atk avg_sp_def
## <dbl> <dbl>
## 1 71.5 70.8
# add average sp_atk and sp_def as black point
ggplot() +
geom_point(data = pokemon,
aes(x = sp_atk, y = sp_def),
colour = "orange",
size = 2.5) +
geom_point(data = avg_sp,
aes(x = avg_sp_atk, y = avg_sp_def),
size = 2.5)

The last quirk we will look at is adding to a ggplot visualisation
after you have assigned it a name. This is very common in tutorials and
on Stack Overflow. A good use of this is to build a base of the x and y
you want to use and test out different geometries.
# saving plot then adding to it
p <- ggplot(pokemon, aes(x = sp_atk, y = sp_def))
p



Quirks of ggplot2 exercise
Make a visualisation of USA athletes ages vs heights, showing the
difference between the genders using colour. When making your
visualisation try to
- Pipe the olympics data to a filter function and select all USA
athletes
- Pipe to a ggplot function
- Add a geom_point function and add the aesthetics there rather than
in
ggplot()
Bar plots with counts
Bar plots are used to show relationships between a numerical and
categorical variable. The categorical variable is usually on the x axis,
and the y axis is usually a frequency count.
By default, bar plots with ggplot only require an x or y axis. From
that they make a frequency count of that variable. See the example
below. First we use ggplot to make a bar plot to count the number of
pokemon added in each generation. Then we do the same thing with dplyr
to make a aggregate table, ggplot is taking this aggregate table and
making into a plot for us!
It is important to make sure your x axis in a bar plot is a factor,
as this helps ggplot to order the axis as you expect.
# make generation a factor
pokemon$generation <- factor(pokemon$generation)
# default bar plot
ggplot(pokemon, aes(x = generation)) +
geom_bar()

# dplyr aggregate equivalent
pokemon %>%
count(generation)
## # A tibble: 8 × 2
## generation n
## <fct> <int>
## 1 1 151
## 2 2 99
## 3 3 141
## 4 4 119
## 5 5 166
## 6 6 84
## 7 7 99
## 8 8 107
To add colour to your bar plot we use the fill argument rather than
colour. This can be confusing, and sometimes if you forget, just try
both till the colours look right! To add our fill manually we add the
fill command to our geom_bar() function.
# manually add fill colour
ggplot(pokemon, aes(generation)) +
geom_bar(fill = "purple")

Just like with the scatter plot, we can colour our plot by a variable
by putting the fill argument within the aes() function. The
below example also shows the equivalent when doing aggregation using
dplyr.
# bar plot with colour by variable
ggplot(pokemon, aes(x = generation, fill = legendary)) +
geom_bar()

# dplyr aggregate equivalent
pokemon %>%
count(generation, legendary)
## # A tibble: 16 × 3
## generation legendary n
## <fct> <lgl> <int>
## 1 1 FALSE 146
## 2 1 TRUE 5
## 3 2 FALSE 94
## 4 2 TRUE 5
## 5 3 FALSE 132
## 6 3 TRUE 9
## 7 4 FALSE 107
## 8 4 TRUE 12
## 9 5 FALSE 158
## 10 5 TRUE 8
## 11 6 FALSE 80
## 12 6 TRUE 4
## 13 7 FALSE 72
## 14 7 TRUE 27
## 15 8 FALSE 99
## 16 8 TRUE 8
Notice in the above example that the bars by default were stacked on
top of each other. We have two other options for changing this with
either a dodge setting (sit next to each other) or a fill setting
(stacked and standarised). To change this we use the position argument
within geom_bar().
# dodge bars
ggplot(pokemon, aes(x = generation, fill = legendary)) +
geom_bar(position = "dodge")

# filled bars
ggplot(pokemon, aes(x = generation, fill = legendary)) +
geom_bar(position = "fill")

A useful thing to change with bar plots is to flip your
coordinates. This is particularly useful if your x axis contains text.
In the example below we will use the type1 variable as our x axis to see
the difference. When we don’t flip the coordinates, the x axis is hard
to read.
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar()

ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip()

To change our colours we use the scale_fill_ function.
This is very similar to what we did with scatter plots except we are
using fill this time, rather than colour.
# change fill with RColorBrewer
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_brewer(palette = "Set1")

# change fill with manual palette
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal)

Currently our plots have the default ggplot theme which has a grey
background. We can change this by setting a new theme. To do so you use
theme_ and select a theme which works best.
# change theme to black and white
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal) +
theme_bw()

# change theme to dark
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal) +
theme_dark()

Adding a theme to each plot can be tiring, so instead you can set a
theme for all your plots by using the theme_set() function.
Usually you set the theme before you make any of your visualisations.
Now we have changed the theme to black and white, all our plots from now
on will have a black and white theme.
# set global theme
theme_set(theme_bw())
# see result
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal)

It is often useful and helpful to arrange the values by their rank or
size. There are options to do this with base R, but the
forcats library from the tidyverse makes arranging and
ordering functions very straightforward.
We will use the fct_infreq() function, which means
factors in frequency, in effect ordering our factors by the frequency
they appear. There are two approaches. First we use the
fct_infreq() function within ggplot, or second we arrange
our factor outside ggplot. Outside of ggplot is usually better as you
have more control and it make your ggplot code easier to read.
# load forcats
library(forcats)
# arrange by frequency within ggplot
ggplot(pokemon, aes(x = fct_infreq(type1), fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal)

# arrange by frequency outside ggplot
pokemon$type1 <- fct_infreq(pokemon$type1)
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal)

We can also reverse the ordering by putting putting our
fct_infreq() function inside a fct_rev()
function (stands for factor reverse).
# arrange by frequency (descending)
pokemon$type1 <- fct_rev(fct_infreq(pokemon$type1))
ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal)

More information on the forcats package can be found here: https://forcats.tidyverse.org/index.html
Finally, let’s save and label our example bar plot.
# save and label
count_type1 <- ggplot(pokemon, aes(x = type1, fill = legendary)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values = manual_pal) +
labs(title = "Frequency of each Pokemon type",
subtitle = "Coloured by if legendary or not",
y = "Frequency of Pokemon type",
x = "Type of Pokemon",
fill = "Legendary pokemon?")
count_type1

ggsave("count_type1.PNG", count_type1)
## Saving 7 x 5 in image
Bar plots with counts exercise
Using the examples above, make a visualisation of the frequency of
ski jump medal winners per country (team) from the Olympics dataset.
Try to include:
- Setting a new theme using
theme_set().
- Order the x axis by the frequency in reverse order. hint:
remember the forcats package
- Make medals a factor, re-order them, and then colour them like we
did in the last exercise.
- Decide if position stack, dodge or fill work best with this
visualisation.
- Add a title and labels.
- Save your visualisation.
Bar plots with other statistics
A very useful function of bar plots is to show a group average
instead of frequency. There are two approaches to showing a group
average in a bar plot.
The first route is aggregate your dataset, then add it into your bar
plot as shown in the example below. We first use group_by()
and summarise() from dplyr to find an average, in this case
the average total statistics by pokemon generation.
We then put this data into ggplot. The difference from a normal bar
plot is we provide a y axis (our calculated average), and add
stat = "identity" to the geom_bar()
function.
This is a great approach as it is easy to see what is happening at
each step, making it simple to identify issues and make changes if
needed.
# group and summarise to make average
avg_total_gen <- pokemon %>%
group_by(generation) %>%
summarise(avg_total = mean(total, na.rm = TRUE))
# print result
avg_total_gen
## # A tibble: 8 × 2
## generation avg_total
## <fct> <dbl>
## 1 1 408.
## 2 2 406.
## 3 3 408.
## 4 4 450.
## 5 5 435.
## 6 6 439.
## 7 7 459.
## 8 8 454.
# add to bar plot with stat identity
ggplot(avg_total_gen, aes(x = generation, y = avg_total)) +
geom_bar(stat = "identity")

The other approach is to use the stat_summary() function
to perform the same plot. The difference from a normal bar plot is we
again provide the y axis but provide the variable we want to aggregate,
total in this case. We then call stat_summary() and add two
arguments, the function we want to use and what type of geometry to use;
we’ve used mean and bar.
While this is less code, which is a good thing, it is hard to
understand the steps taken to make the summary.
ggplot(pokemon, aes(x = generation, y = total)) +
stat_summary(fun = "mean", geom = "bar")

We can also add error bars to our plots to help us understand how
precise our average measure is. To add error bars it is generally easier
to use the group_by and summarise approach. We will look at two types of
error bars, the standard deviation and the standard error of the
mean.
The standard deviation indicates how close sample values are to the
average of all data points, and the accuracy of the average. The
standard error of the mean is the discrepancy of the sample mean and the
true mean, telling you the accuracy of the sample mean.
To calculate, we do the same aggregation as we did before but add sd
(standard deviation) to the summarise function and calculate the sem
(standard error of the mean) in a mutate function.
# group and summarise to make average and sd per group
avg_total_gen <- pokemon %>%
group_by(generation) %>%
summarise(avg_total = mean(total, na.rm = TRUE),
sd = sd(total, na.rm = TRUE)) %>%
mutate(sem = sd/sqrt(length(sd)))
# print result
avg_total_gen
## # A tibble: 8 × 4
## generation avg_total sd sem
## <fct> <dbl> <dbl> <dbl>
## 1 1 408. 99.9 35.3
## 2 2 406. 112. 39.7
## 3 3 408. 117. 41.2
## 4 4 450. 121. 42.7
## 5 5 435. 108. 38.0
## 6 6 439. 116. 40.9
## 7 7 459. 123. 43.6
## 8 8 454. 123. 43.3
To add error bars we use the geom_errorbar() function,
which requires two arguments within an aes() function, the
ymin and ymax. To find ymin or
ymax we plus or minus our avg_total (y axis value) by the
sd/sem.
# adding standard deviation error bars
ggplot(avg_total_gen, aes(x = generation, y = avg_total)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = avg_total-sd, ymax = avg_total+sd)) +
labs(title = "Average Pokemon total statistics by generation",
subtitle = "Error bars indicate standard deviation")

# adding standard error bars
ggplot(avg_total_gen, aes(x = generation, y = avg_total)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = avg_total-sem, ymax = avg_total+sem)) +
labs(title = "Average Pokemon total statistics by generation",
subtitle = "Error bars indicate standard error of the mean")

You can edit the look of the error bars, such as making them narrower
and changing the colour. See the example below on how to do this. We’ve
also changed the colour of the bars too.
ggplot(avg_total_gen, aes(x = generation, y = avg_total)) +
geom_bar(stat = "identity", fill = "orange") +
geom_errorbar(aes(ymin = avg_total-sem, ymax = avg_total+sem), width = 0.3, colour = "darkblue") +
labs(title = "Average Pokemon total statistics by generation",
subtitle = "Error bars indicate standard error of the mean")

If you want to add error bars to bar plots with different groupings
on the x axis we need to made a few subtle changes, the main change is
we need to have a dodge bar chart.
First we will re run our avg_total_gen aggregation and add another
column to our group_by. We then pre-define how wide the bars and error
bars should be. Instead of using position = "dodge" we use
our dodge variable we just made, and add the fill to be legendary (our
second grouping).
# group by legendary as well
avg_total_gen <- pokemon %>%
group_by(generation, legendary) %>%
summarise(avg_total = mean(total, na.rm = TRUE),
sd = sd(total, na.rm = TRUE)) %>%
mutate(sem = sd/sqrt(length(sd)))
## `summarise()` has grouped output by 'generation'. You can override using the
## `.groups` argument.
# pre-define the dodge position
dodge <- position_dodge(width = 0.8)
ggplot(avg_total_gen, aes(x = generation, y = avg_total, fill = legendary)) +
geom_bar(stat = "identity", position = dodge) +
geom_errorbar(aes(ymin = avg_total-sem, ymax = avg_total+sem), position = dodge, width = 0.3) +
labs(title = "Average Pokemon total statistics by generation",
subtitle = "Error bars indicate standard error of the mean") +
scale_fill_manual(values = manual_pal)

Bar plots with other statistics exercise
Using the examples above and the Olympics dataset, make a
visualisation of the average age (mean or median) of GBR (Great Britain)
medal winners by medal type and gender, making sure to
- show the difference between male and female athletes using
colours
- show error bars for either standard deviation or standard error of
the mean
- colour, label and save your visualisation
hint: don’t forgot to use dodge
<- position_dodge(width = 0.8)
Beyond bar plots
Bar plots are not the only option to view aggregated data, and there
are some sources that suggest bar plots are less than ideal for any
visualisation other than showing the frequency of a continuous variable.
See https://paulvanderlaken.com/2018/12/17/avoid-bar-plots-for-continuous-data-do-this-instead/
for details on this.
Fortunately, there are alternatives, such as box plots which will be
covered in the second data visualisation workshop, or we can use scatter
plots! Scatter plots allow us to see all the data and we can add on an
average, the best of both worlds.
In order to recreate what we just did with bar plots with scatter
plots we can either use both geom_point() and
stat_summary(), or make a summary table and add that using
a second geom_point() function. First, lets just plot the
data as a scatter plot, making the points larger and more transparent.
Lowering the transparency (alpha) is important in these plots as darker
colours indicate a higher density of data points.
ggplot(pokemon, aes(x = generation, y = total)) +
geom_point(size = 5, alpha = .33)

Now we can add the stat_summary() function. We are going
to use the mean, the geom is point, and the shape is a the
- symbol (number 95); we will also make the shape larger so
we can see it easier.
# using stat_summary
ggplot(pokemon, aes(x = generation, y = total)) +
geom_point(size = 5, alpha = .33) +
stat_summary(fun = mean, geom = "point",
shape = 95, size = 20)

If we use the summary table option we first make a summary table with
group_by() and summarise(). Then we add two
geom_point() functions. The first has the pokemon data and
our x and y axis. The second is our summary table, with the same x axis
and the avg_total as the y axis.
# summary table option
gen_avg_total <- pokemon %>%
group_by(generation) %>%
summarise(avg_total = mean(total, na.rm = TRUE))
gen_avg_total
## # A tibble: 8 × 2
## generation avg_total
## <fct> <dbl>
## 1 1 408.
## 2 2 406.
## 3 3 408.
## 4 4 450.
## 5 5 435.
## 6 6 439.
## 7 7 459.
## 8 8 454.
ggplot() +
geom_point(data = pokemon,
aes(x = generation, y = total),
size = 5, alpha = .33) +
geom_point(data = gen_avg_total,
aes(x = generation, y = avg_total),
shape = 95, size = 20)

Either option works well, but for the rest of the examples we will
use the stat_summary() option as it is less code.
Now we have all our data so we can see the number of points for each
group, and we can see the average per group!
Finally, we can add colour by our grouped variable (legendary) and
change the colour palette. Just like with the bar plots we can adjust
the positioning from stack to dodge. The examples below show both stack
and dodge versions.
# position stacked
ggplot(pokemon, aes(x = generation, y = total, colour = legendary)) +
geom_point(size = 5, alpha = 0.3) +
stat_summary(fun = mean, geom = "point",
shape = 95, size = 20) +
scale_colour_brewer(palette = "Set1")

# position dodge
dodge <- position_dodge(width = 0.8)
ggplot(pokemon, aes(x = generation, y = total, colour = legendary)) +
geom_point(size = 5, alpha = 0.3, position = dodge) +
stat_summary(fun = mean, geom = "point",
shape = 95, size = 20,
position = dodge) +
scale_colour_brewer(palette = "Set1")

Beyond bar plots exercise
Recreate your last visualisation, average age (mean or median) of GBR
(Great Britain) medal winners by medal type and gender, using the
geom_point() and stat_summary() method
detailed above.
Individual coding challenge
For the individual coding challenge we will be using the food
consumption data from tidy Tuesday: https://github.com/rfordatascience/tidytuesday/blob/master/data/2020/2020-02-18/readme.md.
Use what we have covered in this workshop to make two visualisations
of this dataset:
- A scatter plot showing consumption and co2 emissions for a selected
country (e.g. UK or France)
- A bar plot of average co2 emissions per food category. Display just
six countries to compare, such as UK, France, Germany etc. and colour
them.
Use some of the tips we used and showed to make the visualisations
have labels, colours and look appealing. Try and have some fun with it!
=)
food_consumption <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-02-18/food_consumption.csv')
## Rows: 1430 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): country, food_category
## dbl (2): consumption, co2_emmission
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
food_consumption %>%
glimpse()
## Rows: 1,430
## Columns: 4
## $ country <chr> "Argentina", "Argentina", "Argentina", "Argentina", "Arg…
## $ food_category <chr> "Pork", "Poultry", "Beef", "Lamb & Goat", "Fish", "Eggs"…
## $ consumption <dbl> 10.51, 38.66, 55.48, 1.56, 4.36, 11.39, 195.08, 103.11, …
## $ co2_emmission <dbl> 37.20, 41.53, 1712.00, 54.63, 6.96, 10.46, 277.87, 19.66…
Understanding which visualisation to use and when
Sometimes it can be hard to know where to start with a visualisation.
A great first starting point is understanding the options depending on
the data types you have available. This website gives lots of
information and visual guides on this process: https://www.data-to-viz.com/
Seeing what others have done with this data
The Olympics data we used for the exercises today is from the Tidy
Tuesday GitHub repository. Tidy Tuesday is a social data visualisation
challenge that happens every week and is a great way of learning about
data viz.
The the link below to see what others have done and posted about
using the Olympics data. Use it to get some ideas on what else you can
try and do or get some inspiration from others. https://twitter.com/search?lang=en&q=%23tidytuesday%20olympics&src=typed_query
LS0tCnRpdGxlOiAiUiBEYXRhIFZpc3VhbGlzdGlvbiAxOiBEYXRhIHZpeiB3aXRoIGdncGxvdDIiCmF1dGhvcjoKICAgLSBuYW1lOiBBbmRyZXcgTW9sZXMKICAgICBhZmZpbGlhdGlvbjogTGVhcm5pbmcgRGV2ZWxvcGVyLCBEaWdpdGFsIFNraWxscyBMYWIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdGhlbWU6IHJlYWRhYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBrZWVwX21kOiBubwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKLS0tCgojIE9iamVjdGl2ZSBvZiB3b3Jrc2hvcAoKVG8gY3JlYXRlIHNjYXR0ZXIgYW5kIGJhciBwbG90IHZpc3VhbGlzYXRpb25zIHVzaW5nIHRoZSBnZ3Bsb3QyIHBhY2thZ2UuIAoKIyBXaGF0IHRoaXMgd29ya3Nob3Agd2lsbCBjb3ZlcgoKSW4gdGhpcyB3b3Jrc2hvcCwgdGhlIGFpbSBpcyB0byBjb3ZlciBob3cgdG8gdXNlIHRoZSBnZ3Bsb3QyIHBhY2thZ2UuIFdlIHdpbGwgYmUgY292ZXJpbmc6CgotICAgQW4gaW50cm9kdWN0aW9uIHRvIHRoZSBnZ3Bsb3QyIHBhY2thZ2UKLSAgIEhvdyB0byBtYWtlIHNjYXR0ZXIgcGxvdHMgd2l0aCBnZ3Bsb3QyCi0gICBIb3cgdG8gbWFrZSBiYXIgcGxvdHMgd2l0aCBnZ3Bsb3QyCi0gICBIb3cgdG8gY2hhbmdlIGNvbG91cnMgYW5kIG90aGVyIGZlYXR1cmVzIGluIHlvdXIgdmlzdWFsaXNhdGlvbnMgIAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIEludHJvZHVjdGlvbgoKRGF0YSB2aXN1YWxpc2F0aW9uIGlzIGEgd2F5IG9mIGxvb2tpbmcgYXQgeW91ciBkYXRhIHVzaW5nIGdyYXBoaWNzLCB3aGljaCBwcm92aWRlcyBhIGRpZmZlcmVudCBwZXJzcGVjdGl2ZSB0byB5b3VyIGRhdGEuCgpUaGVyZSBhcmUgYSBsb3Qgb2YgZGlmZmVyZW50IG9wdGlvbnMgZm9yIGRhdGEgdmlzdWFsaXN0aW9uIHdpdGggUi4gWW91IGNhbiB1c2UgdGhlIHZpc3VhbGlzYXRpb24gdG9vbHMgdGhhdCBjb21lIHdpdGggUiwgZ2dwbG90IGFuZCBhbGwgaXRzIGV4dGVuc2lvbnMsIG9yIGZvciBpbnRlcmFjdGl2ZSB2aXN1YWxpc2F0aW9ucyB0aGVyZSBpcyB0aGUgcGxvdGx5IGxpYnJhcnkuCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2FuZHJld21vbGVzMi9yVHJhaW5JbnRyb2R1Y3Rpb24vYmxvYi9tYWluL3ItZGF0YS12aXN1YWxpc2F0aW9uLTEvaW1hZ2VzL2dncGxvdDJfZXhwbG9yYXRvcnkucG5nP3Jhdz10cnVlKXt3aWR0aD0iNDM3In0KCkluIHRoaXMgZGF0YSB2aXN1YWxpc2F0aW9uIHNlcmllcyB3ZSB3aWxsIGJlIG1haW5seSBmb2N1c3Npbmcgb24gZ2dwbG90LCBhcyB3ZWxsIGFzIHBsb3RseS4gV2hpbGUgdGhlIHZpc3VhbGlzdGlvbiB0b29scyB0aGF0IGNvbWUgd2l0aCBSIGFyZSB1c2VmdWwsIGdncGxvdCBhbmQgcGxvdGx5IGFyZSBnZW5lcmFsbHkgZWFzaWVyIHRvIHVzZSBhbmQgbWFrZSBncmVhdCB2aXN1YWxpc2F0aW9ucyB3aXRoLiBGb3IgdGhpcyB0dXRvcmlhbCB3ZSB3aWxsIGJlIHVzaW5nIHRoZSBiZWxvdyBwYWNrYWdlczogZ2dwbG90MiwgZHBseXIsIHJlYWRyLCBqYW5pdG9yLiBSdW4gdGhlIGNvZGUgYmVsb3cgdG8gaW5zdGFsbCB0aGUgcGFja2FnZXMgaWYgeW91IGRvbid0IGhhdmUgdGhlbSBpbnN0YWxsZWQgYWxyZWFkeS4KYGBge3IgZXZhbD1GQUxTRX0KIyBpbnN0YWxsIHBhY2thZ2VzCmluc3RhbGwgPC0gYygiZ2dwbG90MiIsICJkcGx5ciIsICJyZWFkciIsCiAgICAgICAgICAgICAiamFuaXRvciIsICJSQ29sb3JCcmV3ZXIiLAogICAgICAgICAgICAgImZvcmNhdHMiKQoKaW5zdGFsbC5wYWNrYWdlcyhpbnN0YWxsLCBOY3B1cyA9IDYpCmBgYAoKVGhlbiB3ZSBuZWVkIHRvIGxvYWQgdGhlbSBpbnRvIG91ciBzZXNzaW9uLiBSdW4gdGhlIGNvZGUgY2h1bmsgYmVsb3cgdG8gbG9hZCBhbGwgdGhlIGxpYnJhcmllcyB5b3Ugd2lsbCBuZWVkLgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIGxvYWQgcGFja2FnZXMKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGZvcmNhdHMpCmBgYAoKIyBXaGF0IGlzIGdncGxvdCBhbmQgaG93IGRvZXMgaXQgd29yaz8KCmdncGxvdDIgaXMgYSBwYWNrYWdlIGZvciBwcm9kdWNpbmcgZ3JhcGhpY3MgdGhhdCB3b3JrcyBieSBjb21iaW5pbmcgaW5kZXBlbmRlbnQgY29tcG9uZW50cyB3aGVuIG1ha2luZyBncmFwaHMsIGtub3duIGFzIGxheWVycy4gVGhpcyBtYWtlcyBnZ3Bsb3QyIGJvdGggdmVyc2F0aWxlIGFuZCBwb3dlcmZ1bDsgeW91IGFyZSBub3QgbGltaXRlZCBieSBhIHNldCBvZiBvcHRpb25zIGJ1dCBpbnN0ZWFkIGNhbiBtYWtlIG5vdmVsIGdyYXBoaWNzIHRvIHN1aXQgeW91ciBuZWVkcy4KCkl0IGlzIGFsc28gaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBnZ3Bsb3QgY2FuIG9ubHkgdXNlIGRhdGEgZnJhbWVzLiBJZiB5b3VyIGRhdGEgaXMgaW4gYW5vdGhlciBmb3JtYXQgeW91IHdpbGwgbmVlZCB0byB0cmFuc2Zvcm0gaXQgaW50byBhIGRhdGEgZnJhbWUgaW4gb3JkZXIgdG8gdXNlIGdncGxvdC4KCkluIG9yZGVyIHRvIHVuZGVyc3RhbmQgaG93IHRoZSBsYXllcnMgd29yayB3ZSB3aWxsIGZpcnN0IGxvYWQgaW4gc29tZSBkYXRhIGZvciBvdXIgZXhhbXBsZXMuIFdlIHdpbGwgdXNlIGRhdGEgZnJvbSB0aGUgUG9rw6ltb24gZ2FtZXMsIHdoaWNoIHdhcyB3ZWIgc2NyYXBlZCBmcm9tIDxodHRwczovL3Bva2Vtb25kYi5uZXQvcG9rZWRleC9hbGw+LgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIGxvYWQgYW5kIGNsZWFuIG5hbWVzCnBva2Vtb24gPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9hbmRyZXdtb2xlczIvd2ViU2NyYXBpbmcvbWFpbi9SL2RhdGEvcG9rZW1vbi5jc3YiKSAlPiUKICBjbGVhbl9uYW1lcygpCiMgcmV2aWV3IGRhdGEKcG9rZW1vbiAlPiUKICBnbGltcHNlKCkKYGBgCgpUaGUgc3ludGF4IGZvciBnZ3Bsb3QgaGFzIHRocmVlIGtleSBjb21wb25lbnRzLiBUaGUgZ2dwbG90IGZ1bmN0aW9uIGNhbGwgKGBnZ3Bsb3QoKWApLCB0aGUgYWVzdGhldGljcyAoY2FsbGVkIGBhZXMoKWApLCBhbmQgdGhlIGdlb21ldHJ5IChjYWxsZWQgZ2VvbXMpIHdoaWNoIHJlZmVycyB0byBzY2F0dGVyLCBiYXIsIG9yIGxpbmUgcGxvdHMgZm9yIGV4YW1wbGUuIFRoZSBuZXh0IHRocmVlIGNvZGUgY2h1bmtzIGJyZWFrIHRoaXMgZG93bi4KCmBgYHtyfQojIGNhbGwgZ2dwbG90MiBhbmQgYWRkIGRhdGEKZ2dwbG90KHBva2Vtb24pCmBgYAoKTm90aWNlIHdlIGp1c3QgZ2V0IGEgZ3JleSBib3guIFdlIGhhdmUganVzdCBsb2FkZWQgb3VyIGRhdGEgaW50byBnZ3Bsb3QgYnV0IG5vdCBtdWNoIGVsc2UhIE5vdyBsZXRzIGFkZCB0aGUgYWVzdGhldGljcyBhbmQgc2VlIHdoYXQgaGFwcGVucy4KClRvbyBhZGQgYWVzdGhldGljcyB3ZSB1c2UgdGhlIGBhZXMoKWAgZnVuY3Rpb24gd2l0aGluIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uLCBhbmQgc3BlY2lmeSB3aGF0IG91ciB4IGFuZCB5IGF4aXMgd2lsbCBiZSB3aXRoIGNvbHVtbiBuYW1lcyBmcm9tIG91ciBkYXRhLCBzcF9hdGsgYW5kIHNwX2RlZiBpbiB0aGlzIGNhc2UuCgpgYGB7cn0KIyBhZGQgYWVzdGhldGljcwpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBzcF9hdGssIHkgPSBzcF9kZWYpKQpgYGAKCkl0IGlzIHN0YXJ0aW5nIHRvIGxvb2sgbW9yZSBsaWtlIGEgdmlzdWFsaXNhdGlvbiBub3csIHdlIGNhbiBzZWUgdGhlIHggYW5kIHkgYXhpcyBsYWJlbHMsIGJ1dCB3ZSBzdGlsbCBoYXZlIG5vIGRhdGEgcG9pbnRzIHNob3dpbmcuIFdlIGhhdmUgdG8gYWRkIGEgZ2VvbWV0cnkgZm9yIHRoYXQgdG8gaGFwcGVuLiBOb3RpY2UgdGhlIHN5bnRheCBoZXJlLCB3ZSB1c2UgdGhlIGArYCBpY29uIHRvIGFkZCBhIGdlb21ldHJ5IHRvIGdncGxvdCwgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIGBnZW9tX3BvaW50KClgIHdoaWNoIG1ha2VzIHNjYXR0ZXIgcGxvdHMuIEFsbCBnZW9tZXRyeSBmdW5jdGlvbnMgc3RhcnQgd2l0aCBgZ2VvbV9gIGFuZCBlbmQgd2l0aCB0aGUgdHlwZSBvZiBnZW9tZXRyeSBzdWNoIGFzIHBvaW50LCBiYXIsIG9yIGxpbmUuCgpgYGB7cn0KIyBwaWNrIHdoaWNoIGdlb21ldHJ5CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IHNwX2F0aywgeSA9IHNwX2RlZikpICsKICBnZW9tX3BvaW50KCkKYGBgCgpUaGlzIGlzIHRoZSBmdW5kYW1lbnRhbCBjb25jZXB0IG9mIGdncGxvdCwgeW91IGNvbnN0cnVjdCB5b3VyIHZpc3VhbGlzYXRpb25zIGluIGxheWVycywgYWRkaW5nIGdlb21ldHJ5IGxheWVycywgYW5kIG90aGVyIGZlYXR1cmVzIGFzIHlvdSBnby4KCiMjIHdoYXQgaXMgZ2dwbG90IGV4ZXJjaXNlCgpVc2luZyB0aGUgcG9rZW1vbiBkYXRhLCBtYWtlIGEgc2NhdHRlciBwbG90IHdpdGggKmhwKiBvbiB0aGUgeCBheGlzIGFuZCAqc3BlZWQqIG9uIHRoZSB5IGF4aXMuCgpgYGB7cn0KIyB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIFNjYXR0ZXIgcGxvdHMKClNjYXR0ZXIgcGxvdHMgYXJlIGZvciBkaXNwbGF5aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gbnVtZXJpYyAob3IgcXVhbnRpdGF0aXZlKSB2YXJpYWJsZXMuIEZvciBlYWNoIGRhdGEgcG9pbnQsIHRoZSB2YWx1ZXMgb2YgaXRzIGZpcnN0IHZhcmlhYmxlIGlzIHJlcHJlc2VudGVkIG9uIHRoZSBYIGF4aXMgYW5kIHRoZSBzZWNvbmQgb24gdGhlIFkgYXhpcy4KClRvIG1ha2UgYSBzY2F0dGVyIHBsb3Qgd2l0aCBnZ3Bsb3QyIHdlIHVzZSB0aGUgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24gbGlrZSB5b3UganVzdCBzYXcuIEluIG9yZGVyIGZvciBnZ3Bsb3QgdG8gbWFrZSBhIHNjYXR0ZXIgcGxvdCwgdGhlIFggYW5kIFkgYXhpcyBtdXN0IGJlIG51bWVyaWMuCgpUaGUgcGxvdCB3ZSBqdXN0IG1hZGUgaW4gdGhlIGV4YW1wbGUgaXMgb2theSBidXQgaXQgY291bGQgZG8gd2l0aCBzb21lIGltcHJvdmluZy4gVGhlcmUgYXJlIHF1aXRlIGEgZmV3IGRpZmZlcmVudCB3YXlzIHRvIGNoYW5nZSB0aGUgYXBwZWFyYW5jZSBvZiBhIHZpc3VhbGlzYXRpb24sIGxldHMgZ28gdGhyb3VnaCB0aGVtLgoKVGhlIGZpcnN0IHRoaW5nIHdlIHdpbGwgbG9vayBhdCBpcyBhZGRpbmcgc29tZSBjb2xvdXIhIFRoZXJlIGFyZSBhIGZldyBvcHRpb25zIGZvciBhZGRpbmcgY29sb3VycyB0byB5b3VyIHBsb3RzLiBZb3UgY2FuIGFkZCB0aGUgbmFtZSwgc3VjaCBhcyByZWQsIG9yIHlvdSBjYW4gdXNlIGEgaGV4IGNvZGUsIG9yIHlvdSBjYW4gdXNlIGEgcHJlLWRlZmluZWQgcGFsZXR0ZS4gVG8gYWRkIGNvbG91ciB0byBhIHNjYXR0ZXIgcGxvdCB3ZSB1c2UgdGhlIGBjb2xvdXIgPWAgYXJndW1lbnQuCgpgYGB7cn0KIyBjb2xvdXIgb2YgcG9pbnRzCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGhwLCB5ID0gc3BlZWQpKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAib3JhbmdlIikKYGBgCgpUbyBjb2xvdXIgeW91ciBwb2ludHMgYnkgYSBncm91cCAob3IgZmFjdG9yKSB3ZSBoYXZlIHRvIGFkZCB0aGUgY29sb3VyIGFyZ3VtZW50IGludG8gdGhlIGBhZXMoKWAgZnVuY3Rpb24uIFRoaXMgYWxsb3dzIHVzIHRvIGhhdmUgZGlmZmVyZW50IGNvbG91cnMgZm9yIGRpZmZlcmVudCBncm91cHMsIHdoaWNoIG1ha2VzIHRoZSBwbG90IG1vcmUgaW5mb3JtYXRpdmUuCgpJbiB0aGUgYmVsb3cgZXhhbXBsZSwgb3VyIGRhdGEgaXMgY29sb3VyZWQgYnkgaWYgYSBwb2tlbW9uIGlzIGNsYXNzaWZpZWQgYXMgbGVnZW5kYXJ5IG9yIG5vdC4KCmBgYHtyfQojIGNvbG91ciBieSBmYWN0b3IKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gaHAsIHkgPSBzcGVlZCwgY29sb3VyID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCldlIGdldCB0aGUgZGVmYXVsdCBnZ3Bsb3QgY29sb3VycyB3aGljaCBhcmUgb2theS4gVGhlcmUgYXJlIGEgZmV3IGRpZmZlcmVudCB3YXlzIG9mIGNoYW5naW5nIHRoZSBjb2xvdXJzLCBhbGwgbWV0aG9kcyB1c2UgdGhlIGBzY2FsZV9gIGZ1bmN0aW9uIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHdheS4gSW4gdGhlIHR3byBleGFtcGxlcyBiZWxvdyB3ZSBoYXZlIGNoYW5nZWQgdGhlIGNvbG91cnMgdXNpbmcgdGhlIFJDb2xvckJyZXdlciBwYWNrYWdlIGFuZCBoYXZlIHNldCB0aGUgY29sb3VycyBtYW51YWxseS4KClJDb2xvckJyZXdlciBjb21lcyB3aXRoIGEgc2V0IG9mIHBhbGV0dGVzIGZvciBkaWZmZXJlbnQgc2l0dWF0aW9ucywgeW91IGNhbiB2aWV3IHRoZW0gYnkgZm9sbG93aW5nIHRoaXMgbGluayA8aHR0cHM6Ly93d3cuci1ncmFwaC1nYWxsZXJ5LmNvbS8zOC1yY29sb3JicmV3ZXJzLXBhbGV0dGVzLmh0bWw+LiBUbyB1c2UgdGhlc2UgcGFsZXR0ZXMgd2l0aCBnZ3Bsb3Qgd2UgdXNlIHRoZSBgc2NhbGVfY29sb3VyX2JyZXdlcigpYCBmdW5jdGlvbiB3aXRoIGFuIGFyZ3VtZW50IGZvciB3aGljaCBwYWxldHRlIHdlIHdhbnQgdG8gdXNlOyBpbiB0aGlzIGV4YW1wbGUgd2UgYXJlIHVzaW5nIFNldDEuCgpgYGB7cn0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCiMgYWRqdXN0aW5nIGNvbG91ciBieSBmYWN0b3IgdXNpbmcgUkNvbG9yQnJld2VyCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGhwLCB5ID0gc3BlZWQsIGNvbG91ciA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikKYGBgCgpUbyBtYWtlIGEgbWFudWFsIHBhbGV0dGUsIHlvdSBmaXJzdCBtYWtlIGEgdmVjdG9yIHdpdGggeW91ciBjb2xvdXJzLCB0byBkbyBzbyBpdCBpcyB1c2VmdWwgdG8gdXNlIGEgY29sb3VyIHBpY2tlciBzdWNoIGFzIDxodHRwOi8vdHJpc3Rlbi5jYS9oY2wtcGlja2VyLyMvaGxjLzYvMS8xNTUzNEMvRTJFMDYyPiBvciA8aHR0cHM6Ly9jb29sb3JzLmNvLz4uIFlvdSBjb3B5IHRoZSBoZXggY29kZSAoY29kZSB3aXRoIFwjIHRoZW4gNiBudW1iZXJzIG9mIGxldHRlcnMpIGFuZCBwYXN0ZSBpdCBpbnRvIHlvdXIgdmVjdG9yIGxpa2UgeW91IGNhbiBzZWUgaW4gdGhlIG1hbnVhbF9wYWwgdmVjdG9yIGJlbG93LiBUbyBhZGQgdGhlIGNvbG91ciB3ZSB1c2UgYHNjYWxlX2NvbG91cl9tYW51YWwoKWAgZnVuY3Rpb24sIGFuZCBzZXQgdGhlIHZhbHVlcyB0byBvdXIgbWFudWFsIHBhbGV0dGUuCgpgYGB7cn0KIyBhZGp1c3RpbmcgY29sb3VyIGJ5IGZhY3RvciB1c2luZyBtYW51YWwgcGFsZXR0ZQptYW51YWxfcGFsIDwtIGMoIiM5MEMwRjgiLCAiI0VBOTY0RSIpCgpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBocCwgeSA9IHNwZWVkLCBjb2xvdXIgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1hbnVhbF9wYWwpCmBgYAoKSXQgaXMgc29tZXRpbWVzIGhlbHBmdWwgdG8gdmlldyB0aGUgcGFsZXR0ZSBiZWZvcmUgdXNpbmcgaXQuIFdlIGNhbiB1c2UgdGhlIHNjYWxlcyBwYWNrYWdlIGZvciB0aGlzLCB3aGljaCBpcyBpbnN0YWxsZWQgd2hlbiB5b3UgaW5zdGFsbCBnZ3Bsb3QyLiBXZSBwcm92aWRlIHRoZSBgc2hvd19jb2woKWAgZnVuY3Rpb24gd2l0aCB0aGUgcGFsZXR0ZSB3ZSB3YW50IHRvIHZpZXcgYW5kIGl0IHJldHVybnMgYSBncmlkIHZpZXcgb2YgdGhlIGNvbG91cnMuIEluIHRoZSBleGFtcGxlIHdlIGxvb2sgYXQgU2V0MSBmcm9tIFJDb2xvckJyZXdlciBhbmQgdGhlIG1hbnVhbCBwYWxldHRlIHdlIGp1c3QgdXNlZC4KCmBgYHtyfQojIGxvYWQgc2NhbGVzCmxpYnJhcnkoc2NhbGVzKQojIHZpZXcgcGFsZXR0ZXMKc2hvd19jb2woUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG4gPSA4LCBuYW1lID0gIlNldDEiKSkKc2hvd19jb2wobWFudWFsX3BhbCkKYGBgCgpBcyB3ZWxsIGFzIGNoYW5naW5nIHRoZSBjb2xvdXIgb2YgdGhlIHBvaW50cywgeW91IGNhbiBjaGFuZ2UgdGhlaXIgc2hhcGUsIHNpemUsIGFuZCB0cmFuc3BhcmVuY3kgKGFscGhhKS4gSnVzdCBsaWtlIHdpdGggY29sb3VyLCB3ZSBjYW4gZGVmaW5lIHRoZSBzaXplLCBzaGFwZSBvciB0cmFuc3BhcmVuY3kgZWl0aGVyIGluIHRoZSBgYWVzKClgIGZ1bmN0aW9uIG9yIGluIGEgYGdlb21fYCBmdW5jdGlvbi4gQnkgYWRkaW5nIHRoZW0gdG8gdGhlIGBnZW9tX2AgZnVuY3Rpb24gd2UgbWFudWFsbHkgY2hhbmdlIHRoZW0uIElmIHdlIHVzZSB0aGVtIGluIGBhZXMoKWAgd2UgaGF2ZSB0byBhc3NvY2lhdGUgdGhlIHNpemUvc2hhcGUvYWxwaGEgd2l0aCBhIHZhcmlhYmxlLgoKU2VlIHRoZSBiZWxvdyBleGFtcGxlLCBmaXJzdCB3ZSBtYW51YWxseSBzZXQgdGhlIHNpemUgYW5kIGFscGhhLiBJbiB0aGUgc2Vjb25kIGV4YW1wbGUgd2Ugc2V0IHRoZSBzaXplIHRvIGJlIGRlZmluZWQgYnkgdGhlIHRvdGFsIGNvbHVtbiBpbiBvdXIgcG9rZW1vbiBkYXRhLCBhbmQgbWFudWFsbHkgc2V0IHRoZSBhbHBoYS4KCmBgYHtyfQojIG1hbnVhbGx5IHNldCBzaXplIGFuZCBhbHBoYQpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBocCwgeSA9IHNwZWVkLCBjb2xvdXIgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNSwgYWxwaGEgPSAwLjYpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCgojIG1hbnVhbGx5IHNldCBhbHBoYSwgc2l6ZSBieSB0b3RhbApnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBocCwgeSA9IHNwZWVkLCBjb2xvdXIgPSBsZWdlbmRhcnksIHNpemUgPSB0b3RhbCkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42KSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQpgYGAKClRvIG1hbnVhbGx5IGNoYW5nZSB0aGUgc2hhcGUgYW5kIHJlcGxhY2UgdGhlIGNpcmNsZXMsIHdlIGdpdmUgdGhlIHNoYXBlIGFyZ3VtZW50IGEgbnVtYmVyLiBFYWNoIG51bWJlciByZXByZXNlbnRzIGEgc2hhcGUsIGxldHRlciwgb3IgbnVtYmVyOyBieSBkZWZhdWx0IGdncGxvdCB1c2VzIHNoYXBlIG51bWJlciAxOS4gV2UgY2FuIGNoYW5nZSB0aGUgc2hhcGUgdG8gYSBzcXVhcmUgZm9yIGV4YW1wbGUgYnkgdXNpbmcgdGhlIG51bWJlciAxNS4KCmBgYHtyfQojIGRlZmF1bHQgc2hhcGUgbnVtYmVyCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGhwLCB5ID0gc3BlZWQsIGNvbG91ciA9IGxlZ2VuZGFyeSwgc2l6ZSA9IHRvdGFsKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIHNoYXBlID0gMTkpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCgojIHNoYXBlIG51bWJlciBmb3Igc3F1YXJlcwpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBocCwgeSA9IHNwZWVkLCBjb2xvdXIgPSBsZWdlbmRhcnksIHNpemUgPSB0b3RhbCkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaGFwZSA9IDE1KSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQpgYGAKClZpZXcgdGhlIGltYWdlIHdpdGggdGhlIHZpc3VhbCBtYXJrZG93biBlZGl0b3IgdG8gc2VlIHdoYXQgbnVtYmVyIHJlcHJlc2VudHMgd2hhdCBzaGFwZSwgbGV0dGVyLCBvciBudW1iZXIuCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2FuZHJld21vbGVzMi9yVHJhaW5JbnRyb2R1Y3Rpb24vYmxvYi9tYWluL3ItZGF0YS12aXN1YWxpc2F0aW9uLTEvaW1hZ2VzL3NoYXBlcy5wbmc/cmF3PXRydWUpe3dpZHRoPSI4MDAiIGhlaWdodD0iOTAwIn0KCkZpbmFsbHkgd2UgY2FuIGFkZCBhIHRpdGxlIGFuZCBzYXZlIG91ciBwbG90ISBXZSd2ZSBkb25lIHR3byB0aGluZ3MgaW4gb3JkZXIgdG8gYWNoaWV2ZSB0aGlzLiBUbyBhZGQgYSB0aXRsZSwgYW5kIGNoYW5nZSBheGlzIGxhYmVscywgd2UgaGF2ZSB1c2VkIHRoZSBgbGFicygpYCBmdW5jdGlvbi4gV2UgYWRkIGFyZ3VtZW50cyBmb3Igd2hhdCB3ZSB3YW50IHRvIGNoYW5nZSwgc3VjaCBhcyBgdGl0bGUgPSAiUG9rZW1vbiBIaXQgUG9pbnRzIHZzIFNwZWVkImAuIFRvIGNoYW5nZSB0aGUgbGVnZW5kIGxhYmVscyB3ZSB1c2UgY29sb3VyIGFuZCBzaXplLCBhcyB3ZSB1c2VkIHRoZXNlIHRvIGRlZmluZSBvdXIgbGVnZW5kIGluIHRoZSBgYWVzKClgIGZ1bmN0aW9uLgoKVG8gc2F2ZSB0aGUgcGxvdCB3ZSBhc3NpZ24gb3VyIGNvZGUgdG8gYSB2YXJpYWJsZSwgdGhlbiB3ZSB1c2UgdGhlIGBnZ3NhdmUoKWAgZnVuY3Rpb24sIHdoaWNoIHJlcXVpcmVzIHdoYXQgeW91IHdhbnQgdG8gY2FsbCB0aGUgZmlsZSBhbmQgdGhlIGZpbGUgZXh0ZW5zaW9uIChlLmcuIHBsb3QuUE5HIG9yIHBsb3QuSlBHKSwgdGhlbiB0aGUgZ2dwbG90IG9iamVjdCB3ZSBjcmVhdGVkLiBSdW4gdGhlIGV4YW1wbGUgYmVsb3csIGFuZCB5b3Ugc2hvdWxkIGdldCBhIGhwX3ZzX3NwZWVkLlBORyBmaWxlIHdoZXJlIHlvdXIgUm1kIGZpbGUgaXMgc2F2ZWQuIFlvdSBjYW4gYWxzbyBhZGp1c3QgdGhlIHNpemUgb2YgdGhlIGltYWdlIHNhdmVkIHVzaW5nIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IGFyZ3VtZW50cy4KCmBgYHtyfQojIHNhdmUgcGxvdCB0byBhIHZhcmlhYmxlCmhwX3ZzX3NwZWVkIDwtIGdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGhwLCB5ID0gc3BlZWQsIGNvbG91ciA9IGxlZ2VuZGFyeSwgc2l6ZSA9IHRvdGFsKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIHNoYXBlID0gMTUpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsKICBsYWJzKHRpdGxlID0gIlBva2Vtb24gSGl0IFBvaW50cyB2cyBTcGVlZCIsCiAgICAgICBzdWJ0aXRsZSA9ICJUYWtlbiBmcm9tIHBva2Vtb25kYi5uZXQiLAogICAgICAgeCA9ICJIaXQgUG9pbnRzIiwKICAgICAgIHkgPSAiU3BlZWQiLAogICAgICAgY29sb3VyID0gIkxlZ2VuYXJ5IHBva2Vtb24/IiwKICAgICAgIHNpemUgPSAiVG90YWwgc3RhdHMiKQoKaHBfdnNfc3BlZWQKCiMgc2F2ZSBwbG90Cmdnc2F2ZSgiaHBfdnNfc3BlZWQuUE5HIiwgaHBfdnNfc3BlZWQpCgojIHNhdmUgd2l0aCBkZWZpbmVkIHdpZHRoIGFuZCBoZWlnaHQKZ2dzYXZlKCJocF92c19zcGVlZC5QTkciLCBocF92c19zcGVlZCwKICAgICAgIHdpZHRoID0gNywgaGVpZ2h0ID0gNC41KQpgYGAKCiMjIFNjYXR0ZXIgcGxvdHMgZXhlcmNpc2UKCkZvciB0aGUgZXhlcmNpc2VzIGluIHRoaXMgd29ya3Nob3Agd2Ugd2lsbCB1c2UgZGF0YSBmcm9tIHRoZSBPbHltcGljcyB0aGF0IGluY2x1ZGVzIGFsbCBPbHltcGljIGdhbWVzIGZyb20gMTg5NiB0aHJvdWdoIHRvIDIwMTYuIE1vcmUgaW5mb3JtYXRpb24gb24gdGhlIGRhdGFzZXQgY2FuIGJlIGZvdW5kIGhlcmUgPGh0dHBzOi8vZ2l0aHViLmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvYmxvYi9tYXN0ZXIvZGF0YS8yMDIxLzIwMjEtMDctMjcvcmVhZG1lLm1kPi4gUnVuIHRoZSBjb2RlIHByb3ZpZGVkIHRvIGxvYWQgdGhlIGxpYnJhcmllcyBhbmQgZGF0YSBpbnRvIFIuCgpXZSB3aWxsIG1ha2UgdHdvIHNjYXR0ZXIgcGxvdHMgZnJvbSB0aGUgT2x5bXBpY3MgZGF0YS4gRm9yIGJvdGggcGxvdHMgd2Ugd2lsbCB1c2UgZHBseXIgdG8gZmlsdGVyIHRoZSBpbmZvcm1hdGlvbiB3ZSBhcmUgaW50ZXJlc3RlZCBpbiwgd2hpY2ggaGFzIGJlZW4gZG9uZSBmb3IgeW91IGluIHRoaXMgZXhlcmNpc2UuIAoKMSkgIFVzaW5nIHRoZSBwcm92aWRlZCBgc2NhdHRlcl9wbG90MWAgZGF0YSwgbWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBPbHltcGljIGd5bW5hc3RzIGhlaWdodHMgKHggYXhpcykgYW5kIHdlaWdodHMgKHkgYXhpcykuCgotICAgQ2hhbmdlIHRoZSBjb2xvdXIgYW5kIHNoYXBlIGFyZ3VtZW50cyB0byB0ZWxsIHVzIHdoYXQgc2V4IHRoZSBneW1uYXN0cyBhcmUuCi0gICBDaGFuZ2UgdGhlIGNvbG91ciBwYWxldHRlIGJ5IG1ha2luZyBhIG1hbnVhbCBvbmUgb3IgdXNpbmcgUkNvbG9yQnJld2VyLgotICAgQmUgc3VyZSB0byBnaXZlIHlvdXIgcGxvdCBhIHRpdGxlLCBhbmQgc2F2ZSB5b3VyIHBsb3QuCgoyKSAgVXNpbmcgdGhlIHByb3ZpZGVkIGBzY2F0dGVyX3Bsb3QyYCBkYXRhLCBtYWtlIGEgc2NhdHRlciBwbG90IG9mIHRoZSBhZ2UgKHkgYXhpcykgb2YgZ3ltbmFzdGljIG1lZGFsIHdpbm5lcnMgYnkgeWVhciAoeCBheGlzKS4gCgotICAgQ29sb3VyIHlvdXIgcGxvdCBieSBtZWRhbCBieSBtYWtpbmcgYSBtYW51YWwgY29sb3VyIHBhbGV0dGUuICpoaW50OiB0aGUgaGV4IGNvZGVzIGZvciBnb2xkLCBzaWx2ZXIgYW5kIGJyb256ZSBhcmU6ICIjRkZENzAwIiwgIiNDMEMwQzAiLCAiI0NEN0YzMiIqCi0gICBVc2Ugc2hhcGUgdG8gdGVsbCB1cyB3aGF0IHNleCB0aGUgZ3ltbmFzdHMgd2VyZS4KLSAgIEJlIHN1cmUgdG8gZ2l2ZSB5b3VyIHBsb3QgYSB0aXRsZSwgYW5kIHNhdmUgeW91ciBwbG90LgoKCmBgYHtyfQojIG1ha2Ugc3VyZSBsaWJyYXJpZXMgYXJlIGxvYWRlZApsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKIyBsb2FkIGluIGRhdGEKb2x5bXBpY3MgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTA3LTI3L29seW1waWNzLmNzdiIpCgpvbHltcGljcyAlPiUgZ2xpbXBzZSgpCgojIGRhdGEgY2xlYW5pbmcgZm9yIGZpcnN0IHNjYXR0ZXIgcGxvdApzY2F0dGVyX3Bsb3QxIDwtIG9seW1waWNzICU+JQogIGZpbHRlcihzcG9ydCA9PSAiR3ltbmFzdGljcyIpCgojIGRhdGEgY2xlYW5pbmcgZm9yIHNlY29uZCBzY2F0dGVyIHBsb3QKc2NhdHRlcl9wbG90MiA8LSBvbHltcGljcyAlPiUKICBmaWx0ZXIoc3BvcnQgPT0gIkd5bW5hc3RpY3MiKSAlPiUKICBmaWx0ZXIoIWlzLm5hKG1lZGFsKSkgJT4lCiAgbXV0YXRlKG1lZGFsID0gZmFjdG9yKG1lZGFsLCBsZXZlbHMgPSBjKCJHb2xkIiwgIlNpbHZlciIsICJCcm9uemUiKSkpCgojIHlvdXIgY29kZSBoZXJlCgpgYGAKCiMgUXVpcmtzIG9mIGdncGxvdDIKClRoZXJlIGFyZSBhIGZldyBxdWlya3MgdG8gYmUgYXdhcmUgb2Ygd2hlbiB1c2luZyBnZ3Bsb3QyIGFuZCB5b3UnbGwgc2VlIGEgZmV3IG9mIHRoZW0gd2hlbiB5b3UgbG9vayBmb3IgZXhhbXBsZXMgb25saW5lLiBJbiBvcmRlciB0byBhaWQgd2l0aCB0aGlzLCB3ZSBjYW4gaGF2ZSBhIGxvb2sgYXQgYSBmZXcgb2YgdGhlbSEKClRoZSBmaXJzdCBxdWlyayBpcyBwaXBpbmcgZGF0YSBpbnRvIGdncGxvdCwgd2hlcmUgeW91IGRvIG5vdCBuZWVkIHRvIGFkZCB5b3VyIGRhdGEgaW50byB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbiBhcyBpdCBpcyBwaXBlZCBpbi4gVGhlIG1haW4gYWR2YW50YWdlIG9mIHRoaXMgYXBwcm9hY2ggaXMgeW91IGNhbiBzdHJpbmcgdG9nZXRoZXIgc29tZSBkYXRhIGNsZWFuaW5nIGFuZCB0aGVuIHBpcGUgdGhlIHJlc3VsdHMgc3RyYWlnaHQgaW50byBnZ3Bsb3QuCgpgYGB7cn0KIyBwaXBpbmcgZGF0YSBpbnRvIGdncGxvdApwb2tlbW9uICU+JQogIGdncGxvdChhZXMoeCA9IHNwX2F0aywgeSA9IHNwX2RlZikpICsKICBnZW9tX3BvaW50KCkKCiMgcGlwaW5nIHdpdGggZmlsdGVyCnBva2Vtb24gJT4lCiAgZmlsdGVyKHR5cGUxID09ICJGaXJlIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3BfYXRrLCB5ID0gc3BfZGVmKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKClRoZSBzZWNvbmQgcXVpcmsgaXMgYWRkaW5nIGFlc3RoZXRpY3MgaW50byBhIGBnZW9tX2AgZnVuY3Rpb24gcmF0aGVyIHRoYW4gdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24uCgpgYGB7cn0KIyBhZGRpbmcgYWVzdGhldGljcyBpbnRvIHRoZSBnZW9tXyBjYWxsCmdncGxvdChwb2tlbW9uKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHNwX2F0aywgeSA9IHNwX2RlZikpCmBgYAoKVGhlIHRoaXJkIHF1aXJrIGlzIHlvdSBjYW4gYWxzbyBhZGQgdGhlIGRhdGEgaW50byB0aGUgYGdlb21fYCBmdW5jdGlvbi4gV2hlbiBkb2luZyBzbyB5b3UgaGF2ZSB0byBoYXZlIGBkYXRhID1gIG90aGVyd2lzZSB5b3Ugd2lsbCBnZXQgYW4gZXJyb3IuCgpgYGB7cn0KIyBhZGRpbmcgZGF0YSBhbmQgYWVzdGhldGljcyBpbnRvIHRoZSBnZW9tXyBjYWxsCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwb2tlbW9uLCBhZXMoeCA9IHNwX2F0aywgeSA9IHNwX2RlZikpCmBgYAoKVGhlIGZvdXJ0aCBxdWlyayByZWxhdGVzIHRvIHRoZSBzZWNvbmQgYW5kIHRoaXJkLCBpbiB0aGF0IHlvdSBjYW4gYWRkIGFlc3RoZXRpY3MgaW50byBhIGBnZW9tX2AgZnVuY3Rpb24gbW9yZSB0aGFuIG9uY2UuIFlvdSBtaWdodCBvY2Nhc2lvbmFsbHkgY29tZSBhY3Jvc3MgdGhpcyBmb3IgbW9yZSBjb21wbGV4IHZpc3VhbGlzYXRpb25zLgoKSW4gdGhlIGV4YW1wbGUgd2Ugd2lsbCBhZGQgdGhlIGF2ZXJhZ2Ugb2Ygb3VyIHggYW5kIHkgdmFyaWFibGVzLiBGaXJzdCB3ZSBtYWtlIGEgc3VtbWFyeSB0YWJsZSB0aGF0IGhhcyB0aGUgYXZlcmFnZXMgb2YgYm90aCBheGlzJ3MsIHVzaW5nIGBzdW1tYXJpc2UoKWAgZnJvbSBkcGx5ci4gVGhlbiB3ZSBhZGQgdHdvIGBnZW9tX3BvaW50KClgIGZ1bmN0aW9ucywgb25lIHdpdGggdGhlIHBva2Vtb24gZGF0YSwgYW5kIG9uZSB3aXRoIG91ciBzdW1tYXJ5IHRhYmxlIGRhdGEuCgpgYGB7cn0KIyB3aHkgYWRkaW5nIGFlc3RoZXRpY3MgaW50byB0aGUgZ2VvbV8gY2FsbAojIGNhbGN1bGF0ZSBtZWFuIG9mIHNwX2F0ayBhbmQgc3BfZGVmCmF2Z19zcCA8LSBwb2tlbW9uICU+JQogIHN1bW1hcmlzZSgKICAgIGF2Z19zcF9hdGsgPSBtZWFuKHNwX2F0aywgbmEucm0gPSBUUlVFKSwKICAgIGF2Z19zcF9kZWYgPSBtZWFuKHNwX2RlZiwgbmEucm0gPSBUUlVFKSkKCmF2Z19zcAoKIyBhZGQgYXZlcmFnZSBzcF9hdGsgYW5kIHNwX2RlZiBhcyBibGFjayBwb2ludApnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcG9rZW1vbiwgCiAgICAgICAgICAgICBhZXMoeCA9IHNwX2F0aywgeSA9IHNwX2RlZiksIAogICAgICAgICAgICAgY29sb3VyID0gIm9yYW5nZSIsCiAgICAgICAgICAgICBzaXplID0gMi41KSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXZnX3NwLCAKICAgICAgICAgICAgIGFlcyh4ID0gYXZnX3NwX2F0aywgeSA9IGF2Z19zcF9kZWYpLAogICAgICAgICAgICAgc2l6ZSA9IDIuNSkKYGBgCgpUaGUgbGFzdCBxdWlyayB3ZSB3aWxsIGxvb2sgYXQgaXMgYWRkaW5nIHRvIGEgZ2dwbG90IHZpc3VhbGlzYXRpb24gYWZ0ZXIgeW91IGhhdmUgYXNzaWduZWQgaXQgYSBuYW1lLiBUaGlzIGlzIHZlcnkgY29tbW9uIGluIHR1dG9yaWFscyBhbmQgb24gU3RhY2sgT3ZlcmZsb3cuIEEgZ29vZCB1c2Ugb2YgdGhpcyBpcyB0byBidWlsZCBhIGJhc2Ugb2YgdGhlIHggYW5kIHkgeW91IHdhbnQgdG8gdXNlIGFuZCB0ZXN0IG91dCBkaWZmZXJlbnQgZ2VvbWV0cmllcy4KCmBgYHtyfQojIHNhdmluZyBwbG90IHRoZW4gYWRkaW5nIHRvIGl0CnAgPC0gZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gc3BfYXRrLCB5ID0gc3BfZGVmKSkKCnAKCnAgKyBnZW9tX3BvaW50KCkKCnAgKyBnZW9tX2xpbmUoKQpgYGAKCiMgUXVpcmtzIG9mIGdncGxvdDIgZXhlcmNpc2UKCk1ha2UgYSB2aXN1YWxpc2F0aW9uIG9mIFVTQSBhdGhsZXRlcyBhZ2VzIHZzIGhlaWdodHMsIHNob3dpbmcgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZ2VuZGVycyB1c2luZyBjb2xvdXIuIFdoZW4gbWFraW5nIHlvdXIgdmlzdWFsaXNhdGlvbiB0cnkgdG8KCi0gICBQaXBlIHRoZSBvbHltcGljcyBkYXRhIHRvIGEgZmlsdGVyIGZ1bmN0aW9uIGFuZCBzZWxlY3QgYWxsIFVTQSBhdGhsZXRlcwotICAgUGlwZSB0byBhIGdncGxvdCBmdW5jdGlvbgotICAgQWRkIGEgZ2VvbV9wb2ludCBmdW5jdGlvbiBhbmQgYWRkIHRoZSBhZXN0aGV0aWNzIHRoZXJlIHJhdGhlciB0aGFuIGluIGBnZ3Bsb3QoKWAKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCgpgYGAKCiMgQmFyIHBsb3RzIHdpdGggY291bnRzCgpCYXIgcGxvdHMgYXJlIHVzZWQgdG8gc2hvdyByZWxhdGlvbnNoaXBzIGJldHdlZW4gYSBudW1lcmljYWwgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBUaGUgY2F0ZWdvcmljYWwgdmFyaWFibGUgaXMgdXN1YWxseSBvbiB0aGUgeCBheGlzLCBhbmQgdGhlIHkgYXhpcyBpcyB1c3VhbGx5IGEgZnJlcXVlbmN5IGNvdW50LgoKQnkgZGVmYXVsdCwgYmFyIHBsb3RzIHdpdGggZ2dwbG90IG9ubHkgcmVxdWlyZSBhbiB4IG9yIHkgYXhpcy4gRnJvbSB0aGF0IHRoZXkgbWFrZSBhIGZyZXF1ZW5jeSBjb3VudCBvZiB0aGF0IHZhcmlhYmxlLiBTZWUgdGhlIGV4YW1wbGUgYmVsb3cuIEZpcnN0IHdlIHVzZSBnZ3Bsb3QgdG8gbWFrZSBhIGJhciBwbG90IHRvIGNvdW50IHRoZSBudW1iZXIgb2YgcG9rZW1vbiBhZGRlZCBpbiBlYWNoIGdlbmVyYXRpb24uIFRoZW4gd2UgZG8gdGhlIHNhbWUgdGhpbmcgd2l0aCBkcGx5ciB0byBtYWtlIGEgYWdncmVnYXRlIHRhYmxlLCBnZ3Bsb3QgaXMgdGFraW5nIHRoaXMgYWdncmVnYXRlIHRhYmxlIGFuZCBtYWtpbmcgaW50byBhIHBsb3QgZm9yIHVzIQoKSXQgaXMgaW1wb3J0YW50IHRvIG1ha2Ugc3VyZSB5b3VyIHggYXhpcyBpbiBhIGJhciBwbG90IGlzIGEgZmFjdG9yLCBhcyB0aGlzIGhlbHBzIGdncGxvdCB0byBvcmRlciB0aGUgYXhpcyBhcyB5b3UgZXhwZWN0LgoKYGBge3J9CiMgbWFrZSBnZW5lcmF0aW9uIGEgZmFjdG9yCnBva2Vtb24kZ2VuZXJhdGlvbiA8LSBmYWN0b3IocG9rZW1vbiRnZW5lcmF0aW9uKQoKIyBkZWZhdWx0IGJhciBwbG90CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGdlbmVyYXRpb24pKSArCiAgZ2VvbV9iYXIoKQoKIyBkcGx5ciBhZ2dyZWdhdGUgZXF1aXZhbGVudApwb2tlbW9uICU+JQogIGNvdW50KGdlbmVyYXRpb24pCmBgYAoKVG8gYWRkIGNvbG91ciB0byB5b3VyIGJhciBwbG90IHdlIHVzZSB0aGUgZmlsbCBhcmd1bWVudCByYXRoZXIgdGhhbiBjb2xvdXIuIFRoaXMgY2FuIGJlIGNvbmZ1c2luZywgYW5kIHNvbWV0aW1lcyBpZiB5b3UgZm9yZ2V0LCBqdXN0IHRyeSBib3RoIHRpbGwgdGhlIGNvbG91cnMgbG9vayByaWdodCEgVG8gYWRkIG91ciBmaWxsIG1hbnVhbGx5IHdlIGFkZCB0aGUgZmlsbCBjb21tYW5kIHRvIG91ciBgZ2VvbV9iYXIoKWAgZnVuY3Rpb24uCgpgYGB7cn0KIyBtYW51YWxseSBhZGQgZmlsbCBjb2xvdXIKZ2dwbG90KHBva2Vtb24sIGFlcyhnZW5lcmF0aW9uKSkgKwogIGdlb21fYmFyKGZpbGwgPSAicHVycGxlIikKYGBgCgpKdXN0IGxpa2Ugd2l0aCB0aGUgc2NhdHRlciBwbG90LCB3ZSBjYW4gY29sb3VyIG91ciBwbG90IGJ5IGEgdmFyaWFibGUgYnkgcHV0dGluZyB0aGUgZmlsbCBhcmd1bWVudCB3aXRoaW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24uIFRoZSBiZWxvdyBleGFtcGxlIGFsc28gc2hvd3MgdGhlIGVxdWl2YWxlbnQgd2hlbiBkb2luZyBhZ2dyZWdhdGlvbiB1c2luZyBkcGx5ci4KCmBgYHtyfQojIGJhciBwbG90IHdpdGggY29sb3VyIGJ5IHZhcmlhYmxlCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGdlbmVyYXRpb24sIGZpbGwgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9iYXIoKQoKIyBkcGx5ciBhZ2dyZWdhdGUgZXF1aXZhbGVudApwb2tlbW9uICU+JQogIGNvdW50KGdlbmVyYXRpb24sIGxlZ2VuZGFyeSkKYGBgCgpOb3RpY2UgaW4gdGhlIGFib3ZlIGV4YW1wbGUgdGhhdCB0aGUgYmFycyBieSBkZWZhdWx0IHdlcmUgc3RhY2tlZCBvbiB0b3Agb2YgZWFjaCBvdGhlci4gV2UgaGF2ZSB0d28gb3RoZXIgb3B0aW9ucyBmb3IgY2hhbmdpbmcgdGhpcyB3aXRoIGVpdGhlciBhIGRvZGdlIHNldHRpbmcgKHNpdCBuZXh0IHRvIGVhY2ggb3RoZXIpIG9yIGEgZmlsbCBzZXR0aW5nIChzdGFja2VkIGFuZCBzdGFuZGFyaXNlZCkuIFRvIGNoYW5nZSB0aGlzIHdlIHVzZSB0aGUgcG9zaXRpb24gYXJndW1lbnQgd2l0aGluIGBnZW9tX2JhcigpYC4KCmBgYHtyfQojIGRvZGdlIGJhcnMKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gZ2VuZXJhdGlvbiwgZmlsbCA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCiMgZmlsbGVkIGJhcnMKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gZ2VuZXJhdGlvbiwgZmlsbCA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikKYGBgCgpBIHVzZWZ1bCB0aGluZyB0byBjaGFuZ2Ugd2l0aCBiYXIgcGxvdHMgaXMgdG8gKmZsaXAqIHlvdXIgY29vcmRpbmF0ZXMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBpZiB5b3VyIHggYXhpcyBjb250YWlucyB0ZXh0LiBJbiB0aGUgZXhhbXBsZSBiZWxvdyB3ZSB3aWxsIHVzZSB0aGUgdHlwZTEgdmFyaWFibGUgYXMgb3VyIHggYXhpcyB0byBzZWUgdGhlIGRpZmZlcmVuY2UuIFdoZW4gd2UgZG9uJ3QgZmxpcCB0aGUgY29vcmRpbmF0ZXMsIHRoZSB4IGF4aXMgaXMgaGFyZCB0byByZWFkLgoKYGBge3J9CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IHR5cGUxLCBmaWxsID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fYmFyKCkKCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IHR5cGUxLCBmaWxsID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fYmFyKCkgKyAKICBjb29yZF9mbGlwKCkKYGBgCgpUbyBjaGFuZ2Ugb3VyIGNvbG91cnMgd2UgdXNlIHRoZSBgc2NhbGVfZmlsbF9gIGZ1bmN0aW9uLiBUaGlzIGlzIHZlcnkgc2ltaWxhciB0byB3aGF0IHdlIGRpZCB3aXRoIHNjYXR0ZXIgcGxvdHMgZXhjZXB0IHdlIGFyZSB1c2luZyBmaWxsIHRoaXMgdGltZSwgcmF0aGVyIHRoYW4gY29sb3VyLgoKYGBge3J9CiMgY2hhbmdlIGZpbGwgd2l0aCBSQ29sb3JCcmV3ZXIKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gdHlwZTEsIGZpbGwgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikKCiMgY2hhbmdlIGZpbGwgd2l0aCBtYW51YWwgcGFsZXR0ZQpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSB0eXBlMSwgZmlsbCA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX2JhcigpICsgCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtYW51YWxfcGFsKQpgYGAKCkN1cnJlbnRseSBvdXIgcGxvdHMgaGF2ZSB0aGUgZGVmYXVsdCBnZ3Bsb3QgdGhlbWUgd2hpY2ggaGFzIGEgZ3JleSBiYWNrZ3JvdW5kLiBXZSBjYW4gY2hhbmdlIHRoaXMgYnkgc2V0dGluZyBhIG5ldyB0aGVtZS4gVG8gZG8gc28geW91IHVzZSBgdGhlbWVfYCBhbmQgc2VsZWN0IGEgdGhlbWUgd2hpY2ggd29ya3MgYmVzdC4KCmBgYHtyfQojIGNoYW5nZSB0aGVtZSB0byBibGFjayBhbmQgd2hpdGUKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gdHlwZTEsIGZpbGwgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWFudWFsX3BhbCkgKwogIHRoZW1lX2J3KCkKCiMgY2hhbmdlIHRoZW1lIHRvIGRhcmsKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gdHlwZTEsIGZpbGwgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWFudWFsX3BhbCkgKwogIHRoZW1lX2RhcmsoKQpgYGAKCkFkZGluZyBhIHRoZW1lIHRvIGVhY2ggcGxvdCBjYW4gYmUgdGlyaW5nLCBzbyBpbnN0ZWFkIHlvdSBjYW4gc2V0IGEgdGhlbWUgZm9yIGFsbCB5b3VyIHBsb3RzIGJ5IHVzaW5nIHRoZSBgdGhlbWVfc2V0KClgIGZ1bmN0aW9uLiBVc3VhbGx5IHlvdSBzZXQgdGhlIHRoZW1lIGJlZm9yZSB5b3UgbWFrZSBhbnkgb2YgeW91ciB2aXN1YWxpc2F0aW9ucy4gTm93IHdlIGhhdmUgY2hhbmdlZCB0aGUgdGhlbWUgdG8gYmxhY2sgYW5kIHdoaXRlLCBhbGwgb3VyIHBsb3RzIGZyb20gbm93IG9uIHdpbGwgaGF2ZSBhIGJsYWNrIGFuZCB3aGl0ZSB0aGVtZS4KCmBgYHtyfQojIHNldCBnbG9iYWwgdGhlbWUKdGhlbWVfc2V0KHRoZW1lX2J3KCkpCgojIHNlZSByZXN1bHQKZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gdHlwZTEsIGZpbGwgPSBsZWdlbmRhcnkpKSArCiAgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWFudWFsX3BhbCkKYGBgCgpJdCBpcyBvZnRlbiB1c2VmdWwgYW5kIGhlbHBmdWwgdG8gYXJyYW5nZSB0aGUgdmFsdWVzIGJ5IHRoZWlyIHJhbmsgb3Igc2l6ZS4gVGhlcmUgYXJlIG9wdGlvbnMgdG8gZG8gdGhpcyB3aXRoIGJhc2UgUiwgYnV0IHRoZSBgZm9yY2F0c2AgbGlicmFyeSBmcm9tIHRoZSB0aWR5dmVyc2UgbWFrZXMgYXJyYW5naW5nIGFuZCBvcmRlcmluZyBmdW5jdGlvbnMgdmVyeSBzdHJhaWdodGZvcndhcmQuCgpXZSB3aWxsIHVzZSB0aGUgYGZjdF9pbmZyZXEoKWAgZnVuY3Rpb24sIHdoaWNoIG1lYW5zIGZhY3RvcnMgaW4gZnJlcXVlbmN5LCBpbiBlZmZlY3Qgb3JkZXJpbmcgb3VyIGZhY3RvcnMgYnkgdGhlIGZyZXF1ZW5jeSB0aGV5IGFwcGVhci4gVGhlcmUgYXJlIHR3byBhcHByb2FjaGVzLiBGaXJzdCB3ZSB1c2UgdGhlIGBmY3RfaW5mcmVxKClgIGZ1bmN0aW9uIHdpdGhpbiBnZ3Bsb3QsIG9yIHNlY29uZCB3ZSBhcnJhbmdlIG91ciBmYWN0b3Igb3V0c2lkZSBnZ3Bsb3QuIE91dHNpZGUgb2YgZ2dwbG90IGlzIHVzdWFsbHkgYmV0dGVyIGFzIHlvdSBoYXZlIG1vcmUgY29udHJvbCBhbmQgaXQgbWFrZSB5b3VyIGdncGxvdCBjb2RlIGVhc2llciB0byByZWFkLgoKYGBge3J9CiMgbG9hZCBmb3JjYXRzCmxpYnJhcnkoZm9yY2F0cykKCiMgYXJyYW5nZSBieSBmcmVxdWVuY3kgd2l0aGluIGdncGxvdApnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBmY3RfaW5mcmVxKHR5cGUxKSwgZmlsbCA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX2JhcigpICsgCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtYW51YWxfcGFsKQoKIyBhcnJhbmdlIGJ5IGZyZXF1ZW5jeSBvdXRzaWRlIGdncGxvdApwb2tlbW9uJHR5cGUxIDwtIGZjdF9pbmZyZXEocG9rZW1vbiR0eXBlMSkKCmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IHR5cGUxLCBmaWxsID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fYmFyKCkgKyAKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1hbnVhbF9wYWwpCmBgYAoKV2UgY2FuIGFsc28gcmV2ZXJzZSB0aGUgb3JkZXJpbmcgYnkgcHV0dGluZyBwdXR0aW5nIG91ciBgZmN0X2luZnJlcSgpYCBmdW5jdGlvbiBpbnNpZGUgYSBgZmN0X3JldigpYCBmdW5jdGlvbiAoc3RhbmRzIGZvciBmYWN0b3IgcmV2ZXJzZSkuCgpgYGB7cn0KIyBhcnJhbmdlIGJ5IGZyZXF1ZW5jeSAoZGVzY2VuZGluZykKcG9rZW1vbiR0eXBlMSA8LSBmY3RfcmV2KGZjdF9pbmZyZXEocG9rZW1vbiR0eXBlMSkpCgpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSB0eXBlMSwgZmlsbCA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX2JhcigpICsgCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtYW51YWxfcGFsKQpgYGAKCk1vcmUgaW5mb3JtYXRpb24gb24gdGhlIGZvcmNhdHMgcGFja2FnZSBjYW4gYmUgZm91bmQgaGVyZTogPGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnL2luZGV4Lmh0bWw+CgpGaW5hbGx5LCBsZXQncyBzYXZlIGFuZCBsYWJlbCBvdXIgZXhhbXBsZSBiYXIgcGxvdC4KCmBgYHtyfQojIHNhdmUgYW5kIGxhYmVsCmNvdW50X3R5cGUxIDwtIGdncGxvdChwb2tlbW9uLCBhZXMoeCA9IHR5cGUxLCBmaWxsID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fYmFyKCkgKyAKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1hbnVhbF9wYWwpICsKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBlYWNoIFBva2Vtb24gdHlwZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJDb2xvdXJlZCBieSBpZiBsZWdlbmRhcnkgb3Igbm90IiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IG9mIFBva2Vtb24gdHlwZSIsCiAgICAgICB4ID0gIlR5cGUgb2YgUG9rZW1vbiIsCiAgICAgICBmaWxsID0gIkxlZ2VuZGFyeSBwb2tlbW9uPyIpCgpjb3VudF90eXBlMQoKZ2dzYXZlKCJjb3VudF90eXBlMS5QTkciLCBjb3VudF90eXBlMSkKYGBgCgojIyBCYXIgcGxvdHMgd2l0aCBjb3VudHMgZXhlcmNpc2UKClVzaW5nIHRoZSBleGFtcGxlcyBhYm92ZSwgbWFrZSBhIHZpc3VhbGlzYXRpb24gb2YgdGhlIGZyZXF1ZW5jeSBvZiBza2kganVtcCBtZWRhbCB3aW5uZXJzIHBlciBjb3VudHJ5ICh0ZWFtKSBmcm9tIHRoZSBPbHltcGljcyBkYXRhc2V0LgoKVHJ5IHRvIGluY2x1ZGU6CgotICAgU2V0dGluZyBhIG5ldyB0aGVtZSB1c2luZyBgdGhlbWVfc2V0KClgLgotICAgT3JkZXIgdGhlIHggYXhpcyBieSB0aGUgZnJlcXVlbmN5IGluIHJldmVyc2Ugb3JkZXIuICpoaW50OiByZW1lbWJlciB0aGUgZm9yY2F0cyBwYWNrYWdlKgotICAgTWFrZSBtZWRhbHMgYSBmYWN0b3IsIHJlLW9yZGVyIHRoZW0sIGFuZCB0aGVuIGNvbG91ciB0aGVtIGxpa2Ugd2UgZGlkIGluIHRoZSBsYXN0IGV4ZXJjaXNlLgotICAgRGVjaWRlIGlmIHBvc2l0aW9uIHN0YWNrLCBkb2RnZSBvciBmaWxsIHdvcmsgYmVzdCB3aXRoIHRoaXMgdmlzdWFsaXNhdGlvbi4KLSAgIEFkZCBhIHRpdGxlIGFuZCBsYWJlbHMuCi0gICBTYXZlIHlvdXIgdmlzdWFsaXNhdGlvbi4KCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCgoKYGBgCgojIEJhciBwbG90cyB3aXRoIG90aGVyIHN0YXRpc3RpY3MKCkEgdmVyeSB1c2VmdWwgZnVuY3Rpb24gb2YgYmFyIHBsb3RzIGlzIHRvIHNob3cgYSBncm91cCBhdmVyYWdlIGluc3RlYWQgb2YgZnJlcXVlbmN5LiBUaGVyZSBhcmUgdHdvIGFwcHJvYWNoZXMgdG8gc2hvd2luZyBhIGdyb3VwIGF2ZXJhZ2UgaW4gYSBiYXIgcGxvdC4KClRoZSBmaXJzdCByb3V0ZSBpcyBhZ2dyZWdhdGUgeW91ciBkYXRhc2V0LCB0aGVuIGFkZCBpdCBpbnRvIHlvdXIgYmFyIHBsb3QgYXMgc2hvd24gaW4gdGhlIGV4YW1wbGUgYmVsb3cuIFdlIGZpcnN0IHVzZSBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpc2UoKWAgZnJvbSBkcGx5ciB0byBmaW5kIGFuIGF2ZXJhZ2UsIGluIHRoaXMgY2FzZSB0aGUgYXZlcmFnZSB0b3RhbCBzdGF0aXN0aWNzIGJ5IHBva2Vtb24gZ2VuZXJhdGlvbi4KCldlIHRoZW4gcHV0IHRoaXMgZGF0YSBpbnRvIGdncGxvdC4gVGhlIGRpZmZlcmVuY2UgZnJvbSBhIG5vcm1hbCBiYXIgcGxvdCBpcyB3ZSBwcm92aWRlIGEgeSBheGlzIChvdXIgY2FsY3VsYXRlZCBhdmVyYWdlKSwgYW5kIGFkZCBgc3RhdCA9ICJpZGVudGl0eSJgIHRvIHRoZSBgZ2VvbV9iYXIoKWAgZnVuY3Rpb24uCgpUaGlzIGlzIGEgZ3JlYXQgYXBwcm9hY2ggYXMgaXQgaXMgZWFzeSB0byBzZWUgd2hhdCBpcyBoYXBwZW5pbmcgYXQgZWFjaCBzdGVwLCBtYWtpbmcgaXQgc2ltcGxlIHRvIGlkZW50aWZ5IGlzc3VlcyBhbmQgbWFrZSBjaGFuZ2VzIGlmIG5lZWRlZC4KCmBgYHtyfQojIGdyb3VwIGFuZCBzdW1tYXJpc2UgdG8gbWFrZSBhdmVyYWdlCmF2Z190b3RhbF9nZW4gPC0gcG9rZW1vbiAlPiUKICBncm91cF9ieShnZW5lcmF0aW9uKSAlPiUKICBzdW1tYXJpc2UoYXZnX3RvdGFsID0gbWVhbih0b3RhbCwgbmEucm0gPSBUUlVFKSkKCiMgcHJpbnQgcmVzdWx0CmF2Z190b3RhbF9nZW4KCiMgYWRkIHRvIGJhciBwbG90IHdpdGggc3RhdCBpZGVudGl0eQpnZ3Bsb3QoYXZnX3RvdGFsX2dlbiwgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gYXZnX3RvdGFsKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKClRoZSBvdGhlciBhcHByb2FjaCBpcyB0byB1c2UgdGhlIGBzdGF0X3N1bW1hcnkoKWAgZnVuY3Rpb24gdG8gcGVyZm9ybSB0aGUgc2FtZSBwbG90LiBUaGUgZGlmZmVyZW5jZSBmcm9tIGEgbm9ybWFsIGJhciBwbG90IGlzIHdlIGFnYWluIHByb3ZpZGUgdGhlIHkgYXhpcyBidXQgcHJvdmlkZSB0aGUgdmFyaWFibGUgd2Ugd2FudCB0byBhZ2dyZWdhdGUsIHRvdGFsIGluIHRoaXMgY2FzZS4gV2UgdGhlbiBjYWxsIGBzdGF0X3N1bW1hcnkoKWAgYW5kIGFkZCB0d28gYXJndW1lbnRzLCB0aGUgZnVuY3Rpb24gd2Ugd2FudCB0byB1c2UgYW5kIHdoYXQgdHlwZSBvZiBnZW9tZXRyeSB0byB1c2U7IHdlJ3ZlIHVzZWQgbWVhbiBhbmQgYmFyLgoKV2hpbGUgdGhpcyBpcyBsZXNzIGNvZGUsIHdoaWNoIGlzIGEgZ29vZCB0aGluZywgaXQgaXMgaGFyZCB0byB1bmRlcnN0YW5kIHRoZSBzdGVwcyB0YWtlbiB0byBtYWtlIHRoZSBzdW1tYXJ5LgoKYGBge3J9CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGdlbmVyYXRpb24sIHkgPSB0b3RhbCkpICsKICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gImJhciIpCmBgYAoKV2UgY2FuIGFsc28gYWRkIGVycm9yIGJhcnMgdG8gb3VyIHBsb3RzIHRvIGhlbHAgdXMgdW5kZXJzdGFuZCBob3cgcHJlY2lzZSBvdXIgYXZlcmFnZSBtZWFzdXJlIGlzLiBUbyBhZGQgZXJyb3IgYmFycyBpdCBpcyBnZW5lcmFsbHkgZWFzaWVyIHRvIHVzZSB0aGUgZ3JvdXBfYnkgYW5kIHN1bW1hcmlzZSBhcHByb2FjaC4gV2Ugd2lsbCBsb29rIGF0IHR3byB0eXBlcyBvZiBlcnJvciBiYXJzLCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGFuZCB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4uCgpUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIGluZGljYXRlcyBob3cgY2xvc2Ugc2FtcGxlIHZhbHVlcyBhcmUgdG8gdGhlIGF2ZXJhZ2Ugb2YgYWxsIGRhdGEgcG9pbnRzLCBhbmQgdGhlIGFjY3VyYWN5IG9mIHRoZSBhdmVyYWdlLiBUaGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gaXMgdGhlIGRpc2NyZXBhbmN5IG9mIHRoZSBzYW1wbGUgbWVhbiBhbmQgdGhlIHRydWUgbWVhbiwgdGVsbGluZyB5b3UgdGhlIGFjY3VyYWN5IG9mIHRoZSBzYW1wbGUgbWVhbi4KClRvIGNhbGN1bGF0ZSwgd2UgZG8gdGhlIHNhbWUgYWdncmVnYXRpb24gYXMgd2UgZGlkIGJlZm9yZSBidXQgYWRkIHNkIChzdGFuZGFyZCBkZXZpYXRpb24pIHRvIHRoZSBzdW1tYXJpc2UgZnVuY3Rpb24gYW5kIGNhbGN1bGF0ZSB0aGUgc2VtIChzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbikgaW4gYSBtdXRhdGUgZnVuY3Rpb24uCgpgYGB7cn0KIyBncm91cCBhbmQgc3VtbWFyaXNlIHRvIG1ha2UgYXZlcmFnZSBhbmQgc2QgcGVyIGdyb3VwCmF2Z190b3RhbF9nZW4gPC0gcG9rZW1vbiAlPiUKICBncm91cF9ieShnZW5lcmF0aW9uKSAlPiUKICBzdW1tYXJpc2UoYXZnX3RvdGFsID0gbWVhbih0b3RhbCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2QgPSBzZCh0b3RhbCwgbmEucm0gPSBUUlVFKSkgJT4lCiAgbXV0YXRlKHNlbSA9IHNkL3NxcnQobGVuZ3RoKHNkKSkpCgojIHByaW50IHJlc3VsdAphdmdfdG90YWxfZ2VuCmBgYAoKVG8gYWRkIGVycm9yIGJhcnMgd2UgdXNlIHRoZSBgZ2VvbV9lcnJvcmJhcigpYCBmdW5jdGlvbiwgd2hpY2ggcmVxdWlyZXMgdHdvIGFyZ3VtZW50cyB3aXRoaW4gYW4gYGFlcygpYCBmdW5jdGlvbiwgdGhlIGB5bWluYCBhbmQgYHltYXhgLiBUbyBmaW5kIGB5bWluYCBvciBgeW1heGAgd2UgcGx1cyBvciBtaW51cyBvdXIgYXZnX3RvdGFsICh5IGF4aXMgdmFsdWUpIGJ5IHRoZSBzZC9zZW0uCgpgYGB7cn0KIyBhZGRpbmcgc3RhbmRhcmQgZGV2aWF0aW9uIGVycm9yIGJhcnMKZ2dwbG90KGF2Z190b3RhbF9nZW4sIGFlcyh4ID0gZ2VuZXJhdGlvbiwgeSA9IGF2Z190b3RhbCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBhdmdfdG90YWwtc2QsIHltYXggPSBhdmdfdG90YWwrc2QpKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIFBva2Vtb24gdG90YWwgc3RhdGlzdGljcyBieSBnZW5lcmF0aW9uIiwKICAgICAgIHN1YnRpdGxlID0gIkVycm9yIGJhcnMgaW5kaWNhdGUgc3RhbmRhcmQgZGV2aWF0aW9uIikKCiMgYWRkaW5nIHN0YW5kYXJkIGVycm9yIGJhcnMKZ2dwbG90KGF2Z190b3RhbF9nZW4sIGFlcyh4ID0gZ2VuZXJhdGlvbiwgeSA9IGF2Z190b3RhbCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBhdmdfdG90YWwtc2VtLCB5bWF4ID0gYXZnX3RvdGFsK3NlbSkpICsKICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgUG9rZW1vbiB0b3RhbCBzdGF0aXN0aWNzIGJ5IGdlbmVyYXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiRXJyb3IgYmFycyBpbmRpY2F0ZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbiIpCmBgYAoKWW91IGNhbiBlZGl0IHRoZSBsb29rIG9mIHRoZSBlcnJvciBiYXJzLCBzdWNoIGFzIG1ha2luZyB0aGVtIG5hcnJvd2VyIGFuZCBjaGFuZ2luZyB0aGUgY29sb3VyLiBTZWUgdGhlIGV4YW1wbGUgYmVsb3cgb24gaG93IHRvIGRvIHRoaXMuIFdlJ3ZlIGFsc28gY2hhbmdlZCB0aGUgY29sb3VyIG9mIHRoZSBiYXJzIHRvby4KCmBgYHtyfQpnZ3Bsb3QoYXZnX3RvdGFsX2dlbiwgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gYXZnX3RvdGFsKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIm9yYW5nZSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gYXZnX3RvdGFsLXNlbSwgeW1heCA9IGF2Z190b3RhbCtzZW0pLCB3aWR0aCA9IDAuMywgY29sb3VyID0gImRhcmtibHVlIikgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBQb2tlbW9uIHRvdGFsIHN0YXRpc3RpY3MgYnkgZ2VuZXJhdGlvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJFcnJvciBiYXJzIGluZGljYXRlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIikKYGBgCgpJZiB5b3Ugd2FudCB0byBhZGQgZXJyb3IgYmFycyB0byBiYXIgcGxvdHMgd2l0aCBkaWZmZXJlbnQgZ3JvdXBpbmdzIG9uIHRoZSB4IGF4aXMgd2UgbmVlZCB0byBtYWRlIGEgZmV3IHN1YnRsZSBjaGFuZ2VzLCB0aGUgbWFpbiBjaGFuZ2UgaXMgd2UgbmVlZCB0byBoYXZlIGEgZG9kZ2UgYmFyIGNoYXJ0LgoKRmlyc3Qgd2Ugd2lsbCByZSBydW4gb3VyIGF2Z190b3RhbF9nZW4gYWdncmVnYXRpb24gYW5kIGFkZCBhbm90aGVyIGNvbHVtbiB0byBvdXIgZ3JvdXBfYnkuIFdlIHRoZW4gcHJlLWRlZmluZSBob3cgd2lkZSB0aGUgYmFycyBhbmQgZXJyb3IgYmFycyBzaG91bGQgYmUuIEluc3RlYWQgb2YgdXNpbmcgYHBvc2l0aW9uID0gImRvZGdlImAgd2UgdXNlIG91ciBkb2RnZSB2YXJpYWJsZSB3ZSBqdXN0IG1hZGUsIGFuZCBhZGQgdGhlIGZpbGwgdG8gYmUgbGVnZW5kYXJ5IChvdXIgc2Vjb25kIGdyb3VwaW5nKS4KCmBgYHtyfQojIGdyb3VwIGJ5IGxlZ2VuZGFyeSBhcyB3ZWxsCmF2Z190b3RhbF9nZW4gPC0gcG9rZW1vbiAlPiUKICBncm91cF9ieShnZW5lcmF0aW9uLCBsZWdlbmRhcnkpICU+JQogIHN1bW1hcmlzZShhdmdfdG90YWwgPSBtZWFuKHRvdGFsLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzZCA9IHNkKHRvdGFsLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBtdXRhdGUoc2VtID0gc2Qvc3FydChsZW5ndGgoc2QpKSkKCiMgcHJlLWRlZmluZSB0aGUgZG9kZ2UgcG9zaXRpb24KZG9kZ2UgPC0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpCgpnZ3Bsb3QoYXZnX3RvdGFsX2dlbiwgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gYXZnX3RvdGFsLCBmaWxsID0gbGVnZW5kYXJ5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IGRvZGdlKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGF2Z190b3RhbC1zZW0sIHltYXggPSBhdmdfdG90YWwrc2VtKSwgcG9zaXRpb24gPSBkb2RnZSwgd2lkdGggPSAwLjMpICsKICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgUG9rZW1vbiB0b3RhbCBzdGF0aXN0aWNzIGJ5IGdlbmVyYXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiRXJyb3IgYmFycyBpbmRpY2F0ZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbiIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtYW51YWxfcGFsKQpgYGAKCiMjIEJhciBwbG90cyB3aXRoIG90aGVyIHN0YXRpc3RpY3MgZXhlcmNpc2UKClVzaW5nIHRoZSBleGFtcGxlcyBhYm92ZSBhbmQgdGhlIE9seW1waWNzIGRhdGFzZXQsIG1ha2UgYSB2aXN1YWxpc2F0aW9uIG9mIHRoZSBhdmVyYWdlIGFnZSAobWVhbiBvciBtZWRpYW4pIG9mIEdCUiAoR3JlYXQgQnJpdGFpbikgbWVkYWwgd2lubmVycyBieSBtZWRhbCB0eXBlIGFuZCBnZW5kZXIsIG1ha2luZyBzdXJlIHRvCgotICAgc2hvdyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG1hbGUgYW5kIGZlbWFsZSBhdGhsZXRlcyB1c2luZyBjb2xvdXJzCi0gICBzaG93IGVycm9yIGJhcnMgZm9yIGVpdGhlciBzdGFuZGFyZCBkZXZpYXRpb24gb3Igc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4KLSAgIGNvbG91ciwgbGFiZWwgYW5kIHNhdmUgeW91ciB2aXN1YWxpc2F0aW9uCgoqaGludDogZG9uJ3QgZm9yZ290IHRvIHVzZSBkb2RnZSBgPC0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpYCoKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCgpgYGAKCiMgQmV5b25kIGJhciBwbG90cwoKQmFyIHBsb3RzIGFyZSBub3QgdGhlIG9ubHkgb3B0aW9uIHRvIHZpZXcgYWdncmVnYXRlZCBkYXRhLCBhbmQgdGhlcmUgYXJlIHNvbWUgc291cmNlcyB0aGF0IHN1Z2dlc3QgYmFyIHBsb3RzIGFyZSBsZXNzIHRoYW4gaWRlYWwgZm9yIGFueSB2aXN1YWxpc2F0aW9uIG90aGVyIHRoYW4gc2hvd2luZyB0aGUgZnJlcXVlbmN5IG9mIGEgY29udGludW91cyB2YXJpYWJsZS4gU2VlIDxodHRwczovL3BhdWx2YW5kZXJsYWtlbi5jb20vMjAxOC8xMi8xNy9hdm9pZC1iYXItcGxvdHMtZm9yLWNvbnRpbnVvdXMtZGF0YS1kby10aGlzLWluc3RlYWQvPiBmb3IgZGV0YWlscyBvbiB0aGlzLgoKRm9ydHVuYXRlbHksIHRoZXJlIGFyZSBhbHRlcm5hdGl2ZXMsIHN1Y2ggYXMgYm94IHBsb3RzIHdoaWNoIHdpbGwgYmUgY292ZXJlZCBpbiB0aGUgc2Vjb25kIGRhdGEgdmlzdWFsaXNhdGlvbiB3b3Jrc2hvcCwgb3Igd2UgY2FuIHVzZSBzY2F0dGVyIHBsb3RzISBTY2F0dGVyIHBsb3RzIGFsbG93IHVzIHRvIHNlZSBhbGwgdGhlIGRhdGEgYW5kIHdlIGNhbiBhZGQgb24gYW4gYXZlcmFnZSwgdGhlIGJlc3Qgb2YgYm90aCB3b3JsZHMuCgpJbiBvcmRlciB0byByZWNyZWF0ZSB3aGF0IHdlIGp1c3QgZGlkIHdpdGggYmFyIHBsb3RzIHdpdGggc2NhdHRlciBwbG90cyB3ZSBjYW4gZWl0aGVyIHVzZSBib3RoIGBnZW9tX3BvaW50KClgIGFuZCBgc3RhdF9zdW1tYXJ5KClgLCBvciBtYWtlIGEgc3VtbWFyeSB0YWJsZSBhbmQgYWRkIHRoYXQgdXNpbmcgYSBzZWNvbmQgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24uIEZpcnN0LCBsZXRzIGp1c3QgcGxvdCB0aGUgZGF0YSBhcyBhIHNjYXR0ZXIgcGxvdCwgbWFraW5nIHRoZSBwb2ludHMgbGFyZ2VyIGFuZCBtb3JlIHRyYW5zcGFyZW50LiBMb3dlcmluZyB0aGUgdHJhbnNwYXJlbmN5IChhbHBoYSkgaXMgaW1wb3J0YW50IGluIHRoZXNlIHBsb3RzIGFzIGRhcmtlciBjb2xvdXJzIGluZGljYXRlIGEgaGlnaGVyIGRlbnNpdHkgb2YgZGF0YSBwb2ludHMuCgpgYGB7cn0KZ2dwbG90KHBva2Vtb24sIGFlcyh4ID0gZ2VuZXJhdGlvbiwgeSA9IHRvdGFsKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDUsIGFscGhhID0gLjMzKQpgYGAKCk5vdyB3ZSBjYW4gYWRkIHRoZSBgc3RhdF9zdW1tYXJ5KClgIGZ1bmN0aW9uLiBXZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBtZWFuLCB0aGUgZ2VvbSBpcyBwb2ludCwgYW5kIHRoZSBzaGFwZSBpcyBhIHRoZSBgLWAgc3ltYm9sIChudW1iZXIgOTUpOyB3ZSB3aWxsIGFsc28gbWFrZSB0aGUgc2hhcGUgbGFyZ2VyIHNvIHdlIGNhbiBzZWUgaXQgZWFzaWVyLgoKYGBge3J9CiMgdXNpbmcgc3RhdF9zdW1tYXJ5CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGdlbmVyYXRpb24sIHkgPSB0b3RhbCkpICsKICBnZW9tX3BvaW50KHNpemUgPSA1LCBhbHBoYSA9IC4zMykgKwogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLCBnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgICAgc2hhcGUgPSA5NSwgc2l6ZSA9IDIwKQpgYGAKCklmIHdlIHVzZSB0aGUgc3VtbWFyeSB0YWJsZSBvcHRpb24gd2UgZmlyc3QgbWFrZSBhIHN1bW1hcnkgdGFibGUgd2l0aCBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpc2UoKWAuIFRoZW4gd2UgYWRkIHR3byBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbnMuIFRoZSBmaXJzdCBoYXMgdGhlIHBva2Vtb24gZGF0YSBhbmQgb3VyIHggYW5kIHkgYXhpcy4gVGhlIHNlY29uZCBpcyBvdXIgc3VtbWFyeSB0YWJsZSwgd2l0aCB0aGUgc2FtZSB4IGF4aXMgYW5kIHRoZSBgYXZnX3RvdGFsYCBhcyB0aGUgeSBheGlzLiAKYGBge3J9CiMgc3VtbWFyeSB0YWJsZSBvcHRpb24KZ2VuX2F2Z190b3RhbCA8LSBwb2tlbW9uICU+JQogIGdyb3VwX2J5KGdlbmVyYXRpb24pICU+JQogIHN1bW1hcmlzZShhdmdfdG90YWwgPSBtZWFuKHRvdGFsLCBuYS5ybSA9IFRSVUUpKQoKZ2VuX2F2Z190b3RhbAoKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHBva2Vtb24sCiAgICAgICAgICAgICBhZXMoeCA9IGdlbmVyYXRpb24sIHkgPSB0b3RhbCksCiAgICAgICAgICAgICBzaXplID0gNSwgYWxwaGEgPSAuMzMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBnZW5fYXZnX3RvdGFsLAogICAgICAgICAgICAgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gYXZnX3RvdGFsKSwKICAgICAgICAgICAgIHNoYXBlID0gOTUsIHNpemUgPSAyMCkKCmBgYAoKRWl0aGVyIG9wdGlvbiB3b3JrcyB3ZWxsLCBidXQgZm9yIHRoZSByZXN0IG9mIHRoZSBleGFtcGxlcyB3ZSB3aWxsIHVzZSB0aGUgYHN0YXRfc3VtbWFyeSgpYCBvcHRpb24gYXMgaXQgaXMgbGVzcyBjb2RlLiAKCk5vdyB3ZSBoYXZlIGFsbCBvdXIgZGF0YSBzbyB3ZSBjYW4gc2VlIHRoZSBudW1iZXIgb2YgcG9pbnRzIGZvciBlYWNoIGdyb3VwLCBhbmQgd2UgY2FuIHNlZSB0aGUgYXZlcmFnZSBwZXIgZ3JvdXAhCgpGaW5hbGx5LCB3ZSBjYW4gYWRkIGNvbG91ciBieSBvdXIgZ3JvdXBlZCB2YXJpYWJsZSAobGVnZW5kYXJ5KSBhbmQgY2hhbmdlIHRoZSBjb2xvdXIgcGFsZXR0ZS4gSnVzdCBsaWtlIHdpdGggdGhlIGJhciBwbG90cyB3ZSBjYW4gYWRqdXN0IHRoZSBwb3NpdGlvbmluZyBmcm9tIHN0YWNrIHRvIGRvZGdlLiBUaGUgZXhhbXBsZXMgYmVsb3cgc2hvdyBib3RoIHN0YWNrIGFuZCBkb2RnZSB2ZXJzaW9ucy4KYGBge3J9CiMgcG9zaXRpb24gc3RhY2tlZApnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gdG90YWwsIGNvbG91ciA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSA1LCBhbHBoYSA9IDAuMykgKyAKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICAgIHNoYXBlID0gOTUsIHNpemUgPSAyMCkgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikKCiMgcG9zaXRpb24gZG9kZ2UKZG9kZ2UgPC0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpCgpnZ3Bsb3QocG9rZW1vbiwgYWVzKHggPSBnZW5lcmF0aW9uLCB5ID0gdG90YWwsIGNvbG91ciA9IGxlZ2VuZGFyeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSA1LCBhbHBoYSA9IDAuMywgcG9zaXRpb24gPSBkb2RnZSkgKyAKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICAgIHNoYXBlID0gOTUsIHNpemUgPSAyMCwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBkb2RnZSkgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikKYGBgCgojIyBCZXlvbmQgYmFyIHBsb3RzIGV4ZXJjaXNlCgpSZWNyZWF0ZSB5b3VyIGxhc3QgdmlzdWFsaXNhdGlvbiwgYXZlcmFnZSBhZ2UgKG1lYW4gb3IgbWVkaWFuKSBvZiBHQlIgKEdyZWF0IEJyaXRhaW4pIG1lZGFsIHdpbm5lcnMgYnkgbWVkYWwgdHlwZSBhbmQgZ2VuZGVyLCB1c2luZyB0aGUgYGdlb21fcG9pbnQoKWAgYW5kIGBzdGF0X3N1bW1hcnkoKWAgbWV0aG9kIGRldGFpbGVkIGFib3ZlLgoKYGBge3J9CiMgeW91ciBjb2RlIGhlcmUKCmBgYAoKIyBGaW5hbCB0YXNrIC0gUGxlYXNlIGdpdmUgdXMgeW91ciBpbmRpdmlkdWFsIGZlZWRiYWNrIQoKV2Ugd291bGQgYmUgZ3JhdGVmdWwgaWYgeW91IGNvdWxkIHRha2UgYSBtaW51dGUgYmVmb3JlIHRoZSBlbmQgb2YgdGhlIHdvcmtzaG9wIHNvIHdlIGNhbiBnZXQgeW91ciBmZWVkYmFjayEKCjxodHRwczovL2xzZS5ldS5xdWFsdHJpY3MuY29tL2pmZS9mb3JtL1NWXzZlU3JPVld1aXQyOHFjUz9jb3Vyc2VuYW1lPVIlRGF0YSVWaXN1YWxpc2F0aW9uJTE6JURhdGEldml6JXdpdGglZ2dwbG90MiZ0b3BpYz1SJnByb2c9RFMmdmVyc2lvbj0yMy0yNCZsaW5rPWh0dHBzOi8vbHNlY2xvdWQuc2hhcmVwb2ludC5jb20vOmY6L3MvVEVBTV9BUEQtRFNMLURpZ2l0YWwtU2tpbGxzLVRyYWluZXJzL0Vya0k4SG15UmF4RHBVS01aX1UtbTRvQmt1THgyWGNCUXg0amhXTEVPRkhnLXc/ZT1TT2lnZVU+CgpUaGUgc29sdXRpb25zIHdlIGJlIGF2YWlsYWJsZSBmcm9tIGEgbGluayBhdCB0aGUgZW5kIG9mIHRoZSBzdXJ2ZXkuCgojIEluZGl2aWR1YWwgY29kaW5nIGNoYWxsZW5nZQoKRm9yIHRoZSBpbmRpdmlkdWFsIGNvZGluZyBjaGFsbGVuZ2Ugd2Ugd2lsbCBiZSB1c2luZyB0aGUgZm9vZCBjb25zdW1wdGlvbiBkYXRhIGZyb20gdGlkeSBUdWVzZGF5OiA8aHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9ibG9iL21hc3Rlci9kYXRhLzIwMjAvMjAyMC0wMi0xOC9yZWFkbWUubWQ+LgoKVXNlIHdoYXQgd2UgaGF2ZSBjb3ZlcmVkIGluIHRoaXMgd29ya3Nob3AgdG8gbWFrZSB0d28gdmlzdWFsaXNhdGlvbnMgb2YgdGhpcyBkYXRhc2V0OgoKLSAgIEEgc2NhdHRlciBwbG90IHNob3dpbmcgY29uc3VtcHRpb24gYW5kIGNvMiBlbWlzc2lvbnMgZm9yIGEgc2VsZWN0ZWQgY291bnRyeSAoZS5nLiBVSyBvciBGcmFuY2UpCi0gICBBIGJhciBwbG90IG9mIGF2ZXJhZ2UgY28yIGVtaXNzaW9ucyBwZXIgZm9vZCBjYXRlZ29yeS4gRGlzcGxheSBqdXN0IHNpeCBjb3VudHJpZXMgdG8gY29tcGFyZSwgc3VjaCBhcyBVSywgRnJhbmNlLCBHZXJtYW55IGV0Yy4gYW5kIGNvbG91ciB0aGVtLgoKVXNlIHNvbWUgb2YgdGhlIHRpcHMgd2UgdXNlZCBhbmQgc2hvd2VkIHRvIG1ha2UgdGhlIHZpc3VhbGlzYXRpb25zIGhhdmUgbGFiZWxzLCBjb2xvdXJzIGFuZCBsb29rIGFwcGVhbGluZy4gVHJ5IGFuZCBoYXZlIHNvbWUgZnVuIHdpdGggaXQhID0pCgpgYGB7cn0KZm9vZF9jb25zdW1wdGlvbiA8LSByZWFkcjo6cmVhZF9jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFzdGVyL2RhdGEvMjAyMC8yMDIwLTAyLTE4L2Zvb2RfY29uc3VtcHRpb24uY3N2JykKCmZvb2RfY29uc3VtcHRpb24gJT4lCiAgZ2xpbXBzZSgpCgojIHlvdXIgY29kZSBoZXJlCgpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBVbmRlcnN0YW5kaW5nIHdoaWNoIHZpc3VhbGlzYXRpb24gdG8gdXNlIGFuZCB3aGVuCgpTb21ldGltZXMgaXQgY2FuIGJlIGhhcmQgdG8ga25vdyB3aGVyZSB0byBzdGFydCB3aXRoIGEgdmlzdWFsaXNhdGlvbi4gQSBncmVhdCBmaXJzdCBzdGFydGluZyBwb2ludCBpcyB1bmRlcnN0YW5kaW5nIHRoZSBvcHRpb25zIGRlcGVuZGluZyBvbiB0aGUgZGF0YSB0eXBlcyB5b3UgaGF2ZSBhdmFpbGFibGUuIFRoaXMgd2Vic2l0ZSBnaXZlcyBsb3RzIG9mIGluZm9ybWF0aW9uIGFuZCB2aXN1YWwgZ3VpZGVzIG9uIHRoaXMgcHJvY2VzczogPGh0dHBzOi8vd3d3LmRhdGEtdG8tdml6LmNvbS8+CgojIFNlZWluZyB3aGF0IG90aGVycyBoYXZlIGRvbmUgd2l0aCB0aGlzIGRhdGEKClRoZSBPbHltcGljcyBkYXRhIHdlIHVzZWQgZm9yIHRoZSBleGVyY2lzZXMgdG9kYXkgaXMgZnJvbSB0aGUgVGlkeSBUdWVzZGF5IEdpdEh1YiByZXBvc2l0b3J5LiBUaWR5IFR1ZXNkYXkgaXMgYSBzb2NpYWwgZGF0YSB2aXN1YWxpc2F0aW9uIGNoYWxsZW5nZSB0aGF0IGhhcHBlbnMgZXZlcnkgd2VlayBhbmQgaXMgYSBncmVhdCB3YXkgb2YgbGVhcm5pbmcgYWJvdXQgZGF0YSB2aXouCgpUaGUgdGhlIGxpbmsgYmVsb3cgdG8gc2VlIHdoYXQgb3RoZXJzIGhhdmUgZG9uZSBhbmQgcG9zdGVkIGFib3V0IHVzaW5nIHRoZSBPbHltcGljcyBkYXRhLiBVc2UgaXQgdG8gZ2V0IHNvbWUgaWRlYXMgb24gd2hhdCBlbHNlIHlvdSBjYW4gdHJ5IGFuZCBkbyBvciBnZXQgc29tZSBpbnNwaXJhdGlvbiBmcm9tIG90aGVycy4gPGh0dHBzOi8vdHdpdHRlci5jb20vc2VhcmNoP2xhbmc9ZW4mcT0lMjN0aWR5dHVlc2RheSUyMG9seW1waWNzJnNyYz10eXBlZF9xdWVyeT4KCiMgRnVuIGV4dHJhCgpBcyBhIGZ1biBleHRyYSB5b3UgY2FuIG1hbnVhbGx5IGRldGVybWluZSBzaGFwZXMgaW4geW91ciB2aXN1YWxpc2F0aW9uIHVzaW5nIGBzY2FsZV9zaGFwZV9tYW51YWwoKWAuIFdlJ3ZlIGFsc28gcmVtb3ZlZCB0aGUgZ3VpZGUgd2hpY2ggd2FzIHVubmVjZXNzYXJ5IGJ5IHVzaW5nIGBndWlkZSA9ICJub25lImAuIAoKSW4gdGhlIGV4YW1wbGUgYmVsb3csIGFzIG91ciB4IGF4aXMgaXMgZ2VuZXJhdGlvbiBmcm9tIDEgdG8gOCwgd2UgY2FuIG1ha2UgZ2VuZXJhdGlvbiAxIGhhdmUgYSBzaGFwZSBvZiB0aGUgbnVtYmVyIDEgYW5kIHNvIG9uLiAKYGBge3J9CmdncGxvdChwb2tlbW9uLCBhZXMoeCA9IGdlbmVyYXRpb24sIHkgPSB0b3RhbCwgc2hhcGUgPSBnZW5lcmF0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDUsIGFscGhhID0gLjMzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgICBzaGFwZSA9IDk1LCBzaXplID0gMjApICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYyg0OTo1NiksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gIm5vbmUiKQpgYGAKCiA=